Skip to content

Commit 8f3549c

Browse files
committed
Fix tests
1 parent 7fff82b commit 8f3549c

File tree

2 files changed

+85
-18
lines changed

2 files changed

+85
-18
lines changed

app/jobs/lite/archival_warning_job.rb

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -65,12 +65,13 @@ def mark_warning_sent(user, key)
6565
# Atomic JSONB merge at the SQL level to avoid read-modify-write race conditions
6666
# when multiple job workers process the same user concurrently.
6767
User.where(id: user.id).update_all(
68-
Arel.sql(
69-
"settings = COALESCE(settings, '{}'::jsonb) || " \
70-
"jsonb_build_object('archival_warnings', " \
71-
"COALESCE(settings->'archival_warnings', '{}'::jsonb) || " \
72-
"jsonb_build_object(#{ActiveRecord::Base.connection.quote(key)}, #{ActiveRecord::Base.connection.quote(Time.zone.now.iso8601)}))"
73-
)
68+
ActiveRecord::Base.sanitize_sql_array([
69+
"settings = COALESCE(settings, '{}'::jsonb) || " \
70+
"jsonb_build_object('archival_warnings', " \
71+
"COALESCE(settings->'archival_warnings', '{}'::jsonb) || " \
72+
'jsonb_build_object(?, ?))',
73+
key, Time.zone.now.iso8601
74+
])
7475
)
7576
user.reload
7677
end

e2e/lite/plan-gates.spec.js

Lines changed: 78 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -80,27 +80,23 @@ test.describe("Map Layer Gating", () => {
8080
// Data Retention
8181
// ---------------------------------------------------------------------------
8282
test.describe("Data Retention", () => {
83-
test("shows data window upsell banner on map load", async ({ page }) => {
83+
test("shows data window upsell banner when data is truncated", async ({
84+
page,
85+
}) => {
8486
await page.goto("/map/v2", { waitUntil: "domcontentloaded" })
8587
await waitForMapLibre(page)
8688

87-
const banner = await waitForBanner(
88-
page,
89-
"12 months of searchable history",
90-
10000,
91-
)
89+
// Banner appears when the Lite user has points outside the 12-month window
90+
const banner = await waitForBanner(page, "Showing", 10000)
91+
await expect(banner).toContainText("points")
9292
await expect(banner.locator(".map-upgrade-banner-cta")).toBeVisible()
9393
})
9494

9595
test("banner can be dismissed", async ({ page }) => {
9696
await page.goto("/map/v2", { waitUntil: "domcontentloaded" })
9797
await waitForMapLibre(page)
9898

99-
const banner = await waitForBanner(
100-
page,
101-
"12 months of searchable history",
102-
10000,
103-
)
99+
const banner = await waitForBanner(page, "Showing", 10000)
104100
await banner.locator(".map-upgrade-banner-dismiss").click()
105101
await expect(page.locator(".map-upgrade-banner")).not.toBeVisible()
106102
})
@@ -157,7 +153,7 @@ test.describe("Settings Gating", () => {
157153
// API Write Gating
158154
// ---------------------------------------------------------------------------
159155
test.describe("API Write Gating", () => {
160-
test("POST points returns 403 for Lite user", async ({ page }) => {
156+
test("POST points is allowed for Lite user", async ({ page }) => {
161157
const response = await page.request.post("/api/v1/points", {
162158
headers: {
163159
Authorization: `Bearer ${API_KEYS.LITE_USER}`,
@@ -178,6 +174,76 @@ test.describe("API Write Gating", () => {
178174
},
179175
})
180176

177+
expect(response.status()).toBe(200)
178+
})
179+
180+
test("PUT points returns 403 for Lite user", async ({ page }) => {
181+
// First create a point to get its ID
182+
const createResponse = await page.request.post("/api/v1/points", {
183+
headers: {
184+
Authorization: `Bearer ${API_KEYS.LITE_USER}`,
185+
"Content-Type": "application/json",
186+
},
187+
data: {
188+
locations: [
189+
{
190+
type: "Feature",
191+
geometry: { type: "Point", coordinates: [13.41, 52.53] },
192+
properties: {
193+
timestamp: Math.floor(Date.now() / 1000) - 60,
194+
altitude: 40,
195+
speed: 0,
196+
},
197+
},
198+
],
199+
},
200+
})
201+
const created = await createResponse.json()
202+
const pointId = created.data[0].id
203+
204+
const response = await page.request.put(`/api/v1/points/${pointId}`, {
205+
headers: {
206+
Authorization: `Bearer ${API_KEYS.LITE_USER}`,
207+
"Content-Type": "application/json",
208+
},
209+
data: { point: { latitude: 52.54 } },
210+
})
211+
212+
expect(response.status()).toBe(403)
213+
const body = await response.json()
214+
expect(body.error).toBe("write_api_restricted")
215+
})
216+
217+
test("DELETE points returns 403 for Lite user", async ({ page }) => {
218+
// First create a point to get its ID
219+
const createResponse = await page.request.post("/api/v1/points", {
220+
headers: {
221+
Authorization: `Bearer ${API_KEYS.LITE_USER}`,
222+
"Content-Type": "application/json",
223+
},
224+
data: {
225+
locations: [
226+
{
227+
type: "Feature",
228+
geometry: { type: "Point", coordinates: [13.42, 52.54] },
229+
properties: {
230+
timestamp: Math.floor(Date.now() / 1000) - 120,
231+
altitude: 45,
232+
speed: 0,
233+
},
234+
},
235+
],
236+
},
237+
})
238+
const created = await createResponse.json()
239+
const pointId = created.data[0].id
240+
241+
const response = await page.request.delete(`/api/v1/points/${pointId}`, {
242+
headers: {
243+
Authorization: `Bearer ${API_KEYS.LITE_USER}`,
244+
},
245+
})
246+
181247
expect(response.status()).toBe(403)
182248
const body = await response.json()
183249
expect(body.error).toBe("write_api_restricted")

0 commit comments

Comments
 (0)