Skip to content

Commit

Permalink
Add Playwright tests for API and UI integration
Browse files Browse the repository at this point in the history
  • Loading branch information
raimohanska committed Mar 9, 2024
1 parent 3ada116 commit bac8537
Show file tree
Hide file tree
Showing 3 changed files with 287 additions and 1 deletion.
7 changes: 7 additions & 0 deletions backend/src/oauth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,13 @@ export function setupAuth(app: Express, provider: AuthProvider) {
}
})

app.get("/test-callback", async (req, res) => {
const cookies = new Cookies(req, res)
const returnTo = cookies.get("returnTo") || "/"
setAuthenticatedUser(req, res, { domain: null, email: "[email protected]", name: "Ourboard tester" })
res.redirect(returnTo)
})

function parseReturnPath(req: Request) {
return (req.query.returnTo as string) || "/"
}
Expand Down
2 changes: 1 addition & 1 deletion playwright.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ const config: PlaywrightTestConfig = {
timeout: 60000, // Timeout per test file (default 30000)
retries: ci ? 2 : 0,
use: {
baseURL: "http://localhost:8080",
baseURL: "http://localhost:1337",
actionTimeout: 15000,
trace: "retain-on-failure",
},
Expand Down
279 changes: 279 additions & 0 deletions playwright/src/tests/api.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,279 @@
import { Browser, Page, expect, test } from "@playwright/test"
import { sleep } from "../../../common/src/sleep"
import { BoardPage, navigateToBoard, navigateToNewBoard, semiUniqueId } from "../pages/BoardPage"

async function loginAsTester(page: Page) {
await test.step("Login as tester", async () => {
await page.request.get("/test-callback")
})
}

async function logout(page: Page) {
await test.step("Logout", async () => {
await page.request.get("/logout")
})
}

test.describe("API endpoints", () => {
test("Create and update board", async ({ page, browser }) => {
const { id, accessToken } = await test.step("Create board", async () => {
const response = await page.request.post("/api/v1/board", {
data: {
name: "API test board",
},
})
return await response.json()
})

const board = await navigateToBoard(page, browser, id)

await test.step("Check board name", async () => {
await board.assertBoardName("API test board")
const userPageNoteText = `note-${semiUniqueId()}`
await board.createNoteWithText(100, 200, userPageNoteText)
await board.createArea(100, 400, "API notes")
await board.createArea(550, 400, "More API notes")
})

await test.step("Set board name", async () => {
const response = await page.request.put(`/api/v1/board/${id}`, {
data: {
name: "Updated board name",
},
headers: {
API_TOKEN: accessToken,
},
})
expect(response.status()).toEqual(200)
await board.assertBoardName("Updated board name")
})

const item = await test.step("Add item", async () => {
const response = await page.request.post(`/api/v1/board/${id}/item`, {
data: {
type: "note",
text: "API note",
container: "API notes",
color: "#000000",
},
headers: {
API_TOKEN: accessToken,
},
})
expect(response.status()).toEqual(200)
await expect(board.getNote("API note")).toBeVisible()
return await response.json()
})

await test.step("Update item", async () => {
const response = await page.request.put(`/api/v1/board/${id}/item/${item.id}`, {
data: {
type: "note",
text: "Updated item",
color: "#000000",
},
headers: {
API_TOKEN: accessToken,
},
})
expect(response.status()).toEqual(200)
await expect(board.getNote("Updated item")).toBeVisible()
})

await test.step("Change item container", async () => {
await board.assertItemPosition(board.getNote("Updated item"), 163, 460)
const response = await page.request.put(`/api/v1/board/${id}/item/${item.id}`, {
data: {
type: "note",
text: "Updated item",
color: "#000000",
container: "More API notes",
},
headers: {
API_TOKEN: accessToken,
},
})
expect(response.status()).toEqual(200)
await sleep(1000)
await board.assertItemPosition(board.getNote("Updated item"), 613, 460)
})

await test.step("Get board state", async () => {
const response = await page.request.get(`/api/v1/board/${id}`, {
headers: {
API_TOKEN: accessToken,
},
})
const content = await response.json()
expect(content).toEqual({
board: {
id,
name: "Updated board name",
width: 800,
height: 600,
serial: expect.anything(),
connections: [],
items: expect.anything(),
},
})
})

await test.step("Get board state hierarchy", async () => {
const response = await page.request.get(`/api/v1/board/${id}/hierarchy`, {
headers: {
API_TOKEN: accessToken,
},
})
const content = await response.json()
expect(content).toEqual({
board: {
id,
name: "Updated board name",
width: 800,
height: 600,
serial: expect.anything(),
connections: [],
items: expect.anything(),
},
})
})

await test.step("Get board history", async () => {
const response = await page.request.get(`/api/v1/board/${id}/history`, {
headers: {
API_TOKEN: accessToken,
},
})
const content = await response.json()
expect(content).toEqual(expect.arrayContaining([]))
})

await test.step("Get board as CSV", async () => {
const response = await page.request.get(`/api/v1/board/${id}/csv`, {
headers: {
API_TOKEN: accessToken,
},
})
const content = await response.text()
expect(content).toEqual("More API notes,Updated item\n")
})

await test.step("Set accessPolicy", async () => {
const response = await page.request.put(`/api/v1/board/${id}`, {
data: {
name: "Updated board name",
accessPolicy: {
allowList: [],
publicRead: false,
publicWrite: false,
},
},
headers: {
API_TOKEN: accessToken,
},
})
expect(response.status()).toEqual(200)
await page.reload()
await board.assertStatusMessage("This board is for authorized users only. Click here to sign in.")

expect(
(
await (
await page.request.get(`/api/v1/board/${id}`, {
headers: {
API_TOKEN: accessToken,
},
})
).json()
).board.accessPolicy,
).toEqual({
allowList: [],
publicRead: false,
publicWrite: false,
})
})

await test.step("Update accessPolicy", async () => {
const newAccessPolicy = {
allowList: [{ email: "[email protected]" }],
publicRead: true,
publicWrite: true,
}
const response = await page.request.put(`/api/v1/board/${id}`, {
data: {
name: "Updated board name",
accessPolicy: newAccessPolicy,
},
headers: {
API_TOKEN: accessToken,
},
})
expect(response.status()).toEqual(200)
await page.reload()
await expect(board.getNote("Updated item")).toBeVisible()

expect(
(
await (
await page.request.get(`/api/v1/board/${id}`, {
headers: {
API_TOKEN: accessToken,
},
})
).json()
).board.accessPolicy,
).toEqual(newAccessPolicy)

Check failure on line 225 in playwright/src/tests/api.spec.ts

View workflow job for this annotation

GitHub Actions / test (18.x)

[firefox] › src/tests/api.spec.ts:18:9 › API endpoints › Create and update board

3) [firefox] › src/tests/api.spec.ts:18:9 › API endpoints › Create and update board › Update accessPolicy Error: expect(received).toEqual(expected) // deep equality - Expected - 0 + Received + 2 @@ -1,8 +1,10 @@ Object { "allowList": Array [ Object { + "access": null, + "domain": null, "email": "[email protected]", }, ], "publicRead": true, "publicWrite": true, 223 | ).json() 224 | ).board.accessPolicy, > 225 | ).toEqual(newAccessPolicy) | ^ 226 | }) 227 | }) 228 | at /home/runner/work/ourboard/ourboard/playwright/src/tests/api.spec.ts:225:15 at /home/runner/work/ourboard/ourboard/playwright/src/tests/api.spec.ts:196:9
})
})

test("Create board with accessPolicy", async ({ page, browser }) => {
await test.step("With empty accessPolicy", async () => {
const board = await test.step("Create board and navigate", async () => {
const response = await page.request.post("/api/v1/board", {
data: {
name: "API restricted board",
accessPolicy: {
allowList: [],
},
},
})
const { id, accessToken } = await response.json()
return await navigateToBoard(page, browser, id)
})

await test.step("Verify no UI access", async () => {
await board.assertStatusMessage("This board is for authorized users only. Click here to sign in.")
await loginAsTester(page)
await page.reload()
await board.assertStatusMessage("Sorry, access denied. Click here to sign in with another account.")
await logout(page)
})
})

await test.step("With non-empty accessPolicy", async () => {
const board = await test.step("Create board and navigate", async () => {
const response = await page.request.post("/api/v1/board", {
data: {
name: "API restricted board",
accessPolicy: {
allowList: [{ email: "[email protected]" }],
},
},
})
const { id, accessToken } = await response.json()
return await navigateToBoard(page, browser, id)
})

await test.step("Verify restricted access", async () => {
await board.assertStatusMessage("This board is for authorized users only. Click here to sign in.")

await loginAsTester(page)

await page.reload()
await board.assertBoardName("API restricted board")
})
})
})

test("Get board contents with CRDT text", async ({ page, browser }) => {})
})

0 comments on commit bac8537

Please sign in to comment.