-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
6 changed files
with
390 additions
and
59 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
import path from "node:path"; | ||
import { expect, Page, test as base } from '@playwright/test'; | ||
import { randomBytes, randomUUID } from 'node:crypto'; | ||
|
||
|
||
const fixtures = path.resolve(import.meta.dirname, "./__test_fixtures"); | ||
|
||
export type CreateSceneOptions = { | ||
permissions?: Record<string,null|"none"|"read"|"write">, | ||
autoDelete?:boolean, | ||
} | ||
|
||
type TestFixture = { | ||
adminPage:Page, | ||
userPage:Page, | ||
createScene:(opts?:CreateSceneOptions)=>Promise<string>, | ||
uniqueAccount: {username:string, password:string, uid:number}, | ||
|
||
} | ||
|
||
export {expect} from "@playwright/test"; | ||
|
||
export const test = base.extend<TestFixture>({ | ||
adminPage: async ({browser}, use)=>{ | ||
const ctx = await browser.newContext({ storageState: 'playwright/.auth/admin.json', locale: "cimode" }); | ||
const adminPage = await ctx.newPage(); | ||
await use(adminPage); | ||
await ctx.close(); | ||
}, | ||
userPage: async ({browser}, use)=>{ | ||
const ctx = await browser.newContext({ storageState: 'playwright/.auth/user.json', locale: "cimode" }); | ||
const userPage = await ctx.newPage(); | ||
await use(userPage); | ||
await ctx.close(); | ||
}, | ||
/** | ||
* Factory function to create new scenes with random names | ||
* Will _generally_ clean up scenes afterwards | ||
*/ | ||
createScene: async ({browser}, use)=>{ | ||
const fs = await import("node:fs/promises"); | ||
const data = await fs.readFile(path.join(fixtures, "cube.glb")) | ||
const ctx = await browser.newContext({ storageState: 'playwright/.auth/user.json', locale: "cimode" }); | ||
const request = ctx.request; | ||
const names :string[] = []; | ||
await use(async ({permissions, autoDelete=true} :CreateSceneOptions={})=>{ | ||
const name = randomUUID(); | ||
if(autoDelete) names.push(name); | ||
let res = await request.post(`/scenes/${encodeURIComponent(name)}`, { | ||
data, | ||
headers: {"Content-Type": "model/gltf-binary"} | ||
}); | ||
await expect(res).toBeOK(); | ||
//Set expected permissions | ||
if(permissions){ | ||
res = await request.patch(`/scenes/${encodeURIComponent(name)}`, { | ||
data: { | ||
permissions: permissions | ||
} | ||
}); | ||
} | ||
return name; | ||
}); | ||
await Promise.all(names.map(name=> request.delete(`/scenes/${encodeURIComponent(name)}?archive=false`))); | ||
await ctx.close(); | ||
}, | ||
uniqueAccount: async ({browser}, use)=>{ | ||
let username = `testUserLogin${randomBytes(2).readUInt16LE().toString(36)}`; | ||
let password = randomBytes(16).toString("base64"); | ||
let adminContext = await browser.newContext({storageState: "playwright/.auth/admin.json"}); | ||
//Create a user for this specific test | ||
let res = await adminContext.request.post("/users", { | ||
data: JSON.stringify({ | ||
username, | ||
email: `${username}@example.com`, | ||
password, | ||
isAdministrator: false, | ||
}), | ||
headers:{ | ||
"Content-Type": "application/json", | ||
} | ||
}); | ||
let body = JSON.parse(await res.text()); | ||
expect(body).toHaveProperty("uid"); | ||
let uid :number =body.uid; | ||
await use({username, password, uid}); | ||
await adminContext.close(); | ||
}, | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,94 @@ | ||
import path from "node:path"; | ||
|
||
|
||
import { expect, test } from '@playwright/test'; | ||
import { randomUUID } from "node:crypto"; | ||
|
||
const fixtures = path.resolve(import.meta.dirname, "../__test_fixtures"); | ||
|
||
//Authenticated as admin | ||
test.use({ storageState: 'playwright/.auth/admin.json', locale: "cimode" }); | ||
|
||
|
||
|
||
test.skip("can create a new user", async ({page})=>{ | ||
await page.goto("/ui/admin/users"); | ||
|
||
}); | ||
|
||
test.skip("can delete a non-admin user", async ({page})=>{ | ||
|
||
}); | ||
|
||
test("can force-delete archived scenes", async ({page, request})=>{ | ||
|
||
const name = randomUUID(); | ||
const fs = await import("node:fs/promises"); | ||
const data = await fs.readFile(path.join(fixtures, "cube.glb")) | ||
let res = await page.request.post(`/scenes/${encodeURIComponent(name)}`, { | ||
data, | ||
headers: {"Content-Type": "model/gltf-binary"} | ||
}); | ||
await expect(res).toBeOK(); | ||
|
||
res = await page.request.delete(`/scenes/${encodeURIComponent(name)}?archive=true`); | ||
await expect(res).toBeOK(); | ||
|
||
res = await request.get(`/scenes?archived=any&match=${name}`); | ||
let body = await res.json(); | ||
expect(body.scenes).toHaveLength(1); | ||
expect(body.scenes[0]).toHaveProperty("archived", true); | ||
|
||
//There can be any number of archived scenes shown here that leaks from other tests | ||
//But we expect "our" scene to be there and that's what we are looking for | ||
await page.goto("/ui/admin/archives"); | ||
|
||
await expect(page.getByRole("link", {name})).toBeVisible(); | ||
|
||
await page.getByRole("row", {name}).getByRole("button", {name: "labels.delete"}).click(); | ||
|
||
|
||
await expect(page.getByRole("link", {name})).not.toBeVisible(); | ||
|
||
|
||
res = await request.get(`/scenes?archived=any&match=${name}`); | ||
body = await res.json(); | ||
expect(body.scenes).toHaveLength(0); | ||
}); | ||
|
||
test("can restore archived scenes", async ({page, request})=>{ | ||
|
||
const name = randomUUID(); | ||
const fs = await import("node:fs/promises"); | ||
const data = await fs.readFile(path.join(fixtures, "cube.glb")) | ||
let res = await page.request.post(`/scenes/${encodeURIComponent(name)}`, { | ||
data, | ||
headers: {"Content-Type": "model/gltf-binary"} | ||
}); | ||
await expect(res).toBeOK(); | ||
|
||
res = await page.request.delete(`/scenes/${encodeURIComponent(name)}?archive=true`); | ||
await expect(res).toBeOK(); | ||
|
||
res = await request.get(`/scenes?archived=any&match=${name}`); | ||
let body = await res.json(); | ||
expect(body.scenes).toHaveLength(1); | ||
expect(body.scenes[0]).toHaveProperty("archived", true); | ||
|
||
//There can be any number of archived scenes shown here that leaks from other tests | ||
//But we expect "our" scene to be there and that's what we are looking for | ||
await page.goto("/ui/admin/archives"); | ||
|
||
await expect(page.getByRole("link", {name})).toBeVisible(); | ||
|
||
await page.getByRole("row", {name}).getByRole("button", {name: "labels.restore"}).click(); | ||
|
||
|
||
await expect(page.getByRole("link", {name})).not.toBeVisible(); | ||
|
||
|
||
res = await request.get(`/scenes?archived=any&match=${name}`); | ||
body = await res.json(); | ||
expect(body.scenes).toHaveLength(1); | ||
expect(body.scenes[0]).toHaveProperty("archived", false); | ||
}); |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
import path from "node:path"; | ||
import fs from "node:fs/promises"; | ||
import { randomUUID } from "node:crypto"; | ||
|
||
import { test, expect, Page } from '@playwright/test'; | ||
|
||
const fixtures = path.resolve(import.meta.dirname, "../__test_fixtures"); | ||
|
||
//Authenticated as user | ||
test.use({ storageState: 'playwright/.auth/user.json', locale: "cimode" }); | ||
test.describe.configure({ mode: 'serial' }); | ||
|
||
let scenePage: Page; | ||
|
||
const name = randomUUID(); | ||
|
||
|
||
let initial_doc :string; | ||
/** | ||
* Tests in this suite are run in serial mode with no page reload, unless otherwise specified | ||
*/ | ||
test.beforeAll(async ({request, browser})=>{ | ||
//Create a scene | ||
let res = await request.post(`/scenes/${encodeURIComponent(name)}?language=FR`, { | ||
data: await fs.readFile(path.join(fixtures, "cube.glb")), | ||
headers: {"Content-Type": "model/gltf-binary"} | ||
}); | ||
await expect(res).toBeOK(); | ||
|
||
res = await request.get(`/scenes/${encodeURIComponent(name)}/scene.svx.json`); | ||
initial_doc = await res.text(); | ||
|
||
expect(initial_doc).toBeTruthy(); | ||
expect(initial_doc.slice(0,1)).toEqual("{"); //Checks that it appears to be JSON... | ||
|
||
//Make a bunch of changes | ||
res = await request.put(`/scenes/${encodeURIComponent(name)}/articles/new-article-OKiTjtY6zrbJ-EN.html`, { | ||
data: await fs.readFile(path.join(fixtures, "new-article-OKiTjtY6zrbJ-EN.html")), | ||
headers: {"Content-Type": "text/html"} | ||
}); | ||
await expect(res).toBeOK(); | ||
|
||
res = await request.put(`/scenes/${encodeURIComponent(name)}/scene.svx.json`, { | ||
data: await fs.readFile(path.join(fixtures, "scene.svx.json")), | ||
headers: {"Content-Type": "application/json"} | ||
}); | ||
await expect(res).toBeOK(); | ||
|
||
|
||
scenePage = await browser.newPage(); | ||
await scenePage.goto(`/ui/scenes/${name}`); | ||
}); | ||
|
||
|
||
test.afterAll(async () => { | ||
await scenePage.close(); | ||
}); | ||
|
||
|
||
test("can navigate to history page", async ()=>{ | ||
await scenePage.getByRole("link", {name: "buttons.history"}).click(); | ||
await scenePage.waitForURL(`/ui/scenes/${name}/history`); | ||
|
||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
import path from "node:path"; | ||
import fs from "node:fs/promises"; | ||
|
||
|
||
import { expect, test } from '../fixtures'; | ||
import { randomUUID } from "node:crypto"; | ||
|
||
|
||
|
||
test.use({ storageState: {cookies:[], origins: []}, locale: "cimode"}); | ||
|
||
|
||
//Authenticated as user | ||
|
||
|
||
test.describe("author", ()=>{ | ||
|
||
test("can edit his scenes", async ({userPage, createScene})=>{ | ||
let name = await createScene(); | ||
await userPage.goto(`/ui/scenes/${encodeURIComponent(name)}`); | ||
|
||
//Expect "edit" and "history" buttons to be present | ||
await expect(userPage.getByRole("link", {name: "labels.edit", exact: true})).toHaveAttribute("href", `/ui/scenes/${encodeURIComponent(name)}/edit`) | ||
await expect(userPage.getByRole("link", {name: "buttons.history", exact: true})).toHaveAttribute("href", `/ui/scenes/${encodeURIComponent(name)}/history`) | ||
}); | ||
|
||
test("can archive and restore his scenes", async ({userPage, createScene})=>{ | ||
let name = await createScene(); | ||
await userPage.goto(`/ui/scenes/${encodeURIComponent(name)}`); | ||
await userPage.getByRole('button', { name: 'buttons.archive' }).click(); | ||
|
||
//We are now on the archived scene's page | ||
await userPage.waitForURL(/\/ui\/scenes\/.+/); | ||
|
||
//Check it is truly archived | ||
let res = await userPage.request.get(`/ui/scenes/${encodeURIComponent(name)}`); | ||
expect(res.status()).toEqual(404); | ||
|
||
//Default rename target should be our original name | ||
await expect(userPage.locator("#scene-name-input")).toHaveValue(name); | ||
//Decide of a new name for the scene | ||
let newName = randomUUID(); | ||
await userPage.locator("#scene-name-input").fill(newName); | ||
await userPage.getByRole("button", {name: "labels.restore"}).click(); | ||
|
||
await userPage.waitForURL(`/ui/scenes/${newName}`); | ||
}); | ||
}); | ||
|
||
test.describe("admin", ()=>{ | ||
test("can edit other users' scenes", async ({adminPage, createScene})=>{ | ||
let name = await createScene(); | ||
await adminPage.goto(`/ui/scenes/${encodeURIComponent(name)}`); | ||
|
||
//Expect "edit" and "history" buttons to be present | ||
await expect(adminPage.getByRole("link", {name: "labels.edit", exact: true})).toHaveAttribute("href", `/ui/scenes/${encodeURIComponent(name)}/edit`) | ||
await expect(adminPage.getByRole("link", {name: "buttons.history", exact: true})).toHaveAttribute("href", `/ui/scenes/${encodeURIComponent(name)}/history`) | ||
}); | ||
|
||
test("can archive other user's scene", async ({adminPage, createScene})=>{ | ||
let name = await createScene(); | ||
await adminPage.goto(`/ui/scenes/${encodeURIComponent(name)}`); | ||
await adminPage.getByRole('button', { name: 'buttons.archive' }).click() | ||
await adminPage.waitForURL(new RegExp(`/ui/scenes/${name}`)); | ||
|
||
let res = await adminPage.request.get(`/ui/scenes/${encodeURIComponent(name)}`); | ||
expect(res.status()).toEqual(404); | ||
}); | ||
|
||
}); | ||
|
||
test("read-only view", async ({page, createScene})=>{ | ||
let name = await createScene(); | ||
await page.goto(`/ui/scenes/${encodeURIComponent(name)}`); | ||
|
||
//Expect "edit" and "history" buttons to be present | ||
await expect(page.getByRole("link", {name: "labels.view", exact: true})).toBeVisible(); | ||
await expect(page.getByRole("link", {name: "labels.edit", exact: true})).not.toBeVisible(); | ||
await expect(page.getByRole("link", {name: "buttons.history", exact: true})).not.toBeVisible(); | ||
|
||
let res= await page.goto(`/ui/scenes/${encodeURIComponent(name)}/edit`); | ||
expect(res?.status()).toEqual(404); | ||
}); | ||
|
||
|
||
test("404 view", async ({page, createScene})=>{ | ||
let name = await createScene({permissions: {default: "none"}}); | ||
for (let p of ["", "edit", "view", "history"]) { | ||
let res= await page.goto(`/ui/scenes/${encodeURIComponent(name)}/${p}`); | ||
expect(res?.status()).toEqual(404); | ||
} | ||
}); |
Oops, something went wrong.