adds playwright tests
This commit is contained in:
19
web/tests/playwright/auth.setup.ts
Normal file
19
web/tests/playwright/auth.setup.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
import { test as setup } from '@playwright/test';
|
||||
|
||||
const authFile = 'playwright/.auth/user.json';
|
||||
|
||||
setup('authenticate', async ({ page }) => {
|
||||
await page.goto('/login', { waitUntil: 'networkidle' });
|
||||
await page.locator('input[name="username"]').fill('Test');
|
||||
await page.locator('input[name="password"]').fill('password');
|
||||
await page.getByRole('button', { name: 'Login' }).click();
|
||||
// Wait until the page receives the cookies.
|
||||
//
|
||||
// Sometimes login flow sets cookies in the process of several redirects.
|
||||
// Wait for the final URL to ensure that the cookies are actually set.
|
||||
await page.waitForURL('/');
|
||||
|
||||
// End of authentication steps.
|
||||
|
||||
await page.context().storageState({ path: authFile });
|
||||
});
|
||||
8
web/tests/playwright/e2e/index/index.spec.ts
Normal file
8
web/tests/playwright/e2e/index/index.spec.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
import { expect, test } from '@playwright/test';
|
||||
import { IndexPage } from '../../pages/index_page';
|
||||
|
||||
test('index page does not show error', async ({ page }) => {
|
||||
const indexPage = new IndexPage(page);
|
||||
await indexPage.goto()
|
||||
await indexPage.hasNoError()
|
||||
});
|
||||
30
web/tests/playwright/e2e/list/list.spec.ts
Normal file
30
web/tests/playwright/e2e/list/list.spec.ts
Normal file
@@ -0,0 +1,30 @@
|
||||
import { test as base, expect } from '@playwright/test';
|
||||
import { ListsPage } from '../../pages/lists_page';
|
||||
|
||||
const test = base.extend<{ listsPage: ListsPage }>({
|
||||
listsPage: async ({ page }, use) => {
|
||||
const listsPage = new ListsPage(page);
|
||||
await listsPage.goto();
|
||||
await listsPage.create();
|
||||
await use(listsPage);
|
||||
await listsPage.removeAll();
|
||||
},
|
||||
});
|
||||
|
||||
test('shows a list card', async ({ listsPage }) => {
|
||||
const listItemCount = await listsPage.listItems.count();
|
||||
await listsPage.create();
|
||||
expect(listsPage.listItems).toHaveCount(listItemCount + 1);
|
||||
expect(listsPage.listItemsImage).toBeVisible();
|
||||
});
|
||||
|
||||
test('update a list card', async ({ listsPage }) => {
|
||||
await listsPage.update();
|
||||
expect(listsPage.listItems.first()).toContainText("Updated List");
|
||||
expect(listsPage.listItems.first()).toContainText("New Description");
|
||||
});
|
||||
|
||||
test('delete a list card', async ({ listsPage }) => {
|
||||
await listsPage.delete();
|
||||
expect(listsPage.listItems).toHaveCount(0);
|
||||
});
|
||||
11
web/tests/playwright/e2e/user/user.spec.ts
Normal file
11
web/tests/playwright/e2e/user/user.spec.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
import { test, expect } from '@playwright/test';
|
||||
|
||||
test('logs the user out', async ({ page }) => {
|
||||
await page.goto('/');
|
||||
await page.getByRole('button', { name: 'avatar' }).click();
|
||||
await page.locator(".menu .menu-item").filter({ hasText: "Logout" }).click();
|
||||
|
||||
const cookies = await page.context().cookies();
|
||||
const pbAuthCookie = cookies.find(cookie => cookie.name === 'pb_auth');
|
||||
expect(pbAuthCookie).toBeFalsy();
|
||||
});
|
||||
BIN
web/tests/playwright/fixtures/avatar.webp
Normal file
BIN
web/tests/playwright/fixtures/avatar.webp
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 154 KiB |
19
web/tests/playwright/pages/index_page.ts
Normal file
19
web/tests/playwright/pages/index_page.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
import { expect, type Locator, type Page } from '@playwright/test';
|
||||
|
||||
export class IndexPage {
|
||||
readonly page: Page;
|
||||
readonly error: Locator;
|
||||
|
||||
constructor(page: Page) {
|
||||
this.page = page;
|
||||
this.error = page.getByText("Internal Error");
|
||||
}
|
||||
|
||||
async goto() {
|
||||
await this.page.goto('/');
|
||||
}
|
||||
|
||||
async hasNoError() {
|
||||
await expect(this.error).toHaveCount(0);
|
||||
}
|
||||
}
|
||||
83
web/tests/playwright/pages/lists_page.ts
Normal file
83
web/tests/playwright/pages/lists_page.ts
Normal file
@@ -0,0 +1,83 @@
|
||||
import { type Locator, type Page } from '@playwright/test';
|
||||
|
||||
export class ListsPage {
|
||||
readonly page: Page;
|
||||
readonly createListButton: Locator;
|
||||
|
||||
readonly listItems: Locator;
|
||||
readonly listItemsImage: Locator;
|
||||
|
||||
readonly listModal: Locator;
|
||||
readonly listModalAvatar: Locator;
|
||||
readonly listModalName: Locator;
|
||||
readonly listModalDescription: Locator;
|
||||
readonly listModalSaveButton: Locator;
|
||||
|
||||
|
||||
readonly confirmModal: Locator;
|
||||
readonly confirmModalConfirmButton: Locator;
|
||||
|
||||
|
||||
constructor(page: Page) {
|
||||
this.page = page;
|
||||
this.createListButton = page.locator("#create-list-button");
|
||||
this.listModal = page.locator("#list-modal");
|
||||
|
||||
this.listModalAvatar = this.listModal.locator('input[name="avatar"]')
|
||||
this.listModalName = this.listModal.locator('input[name="name"]')
|
||||
this.listModalDescription = this.listModal.locator('textarea[name="description"]')
|
||||
this.listModalSaveButton = this.listModal.getByText('Save');
|
||||
|
||||
this.listItems = page.locator('.list-list-item');
|
||||
this.listItemsImage = page.locator('.list-list-item img');
|
||||
|
||||
|
||||
this.confirmModal = page.locator("#confirm-modal");
|
||||
this.confirmModalConfirmButton = this.confirmModal.locator("button").filter({ hasText: "Delete" });
|
||||
}
|
||||
|
||||
async goto() {
|
||||
await this.page.goto('/lists', { waitUntil: 'networkidle' });
|
||||
}
|
||||
|
||||
async create(name: string = "Test List") {
|
||||
await this.createListButton.click();
|
||||
await this.listModalName.fill(name);
|
||||
await this.listModalAvatar.setInputFiles([
|
||||
"./tests/playwright/fixtures/avatar.webp"
|
||||
]);
|
||||
await Promise.all([
|
||||
this.page.waitForResponse(resp => resp.url().includes('/api/v1/list') && resp.status() === 200),
|
||||
this.listModalSaveButton.click()
|
||||
]);
|
||||
}
|
||||
|
||||
async update(name: string = "Updated List", description = "New Description") {
|
||||
await this.listItems.first().locator(".dropdown button").click();
|
||||
await this.listItems.first().locator(".menu .menu-item").filter({ hasText: "Edit" }).click();
|
||||
await this.listModalName.fill(name);
|
||||
await this.listModalDescription.fill(description);
|
||||
|
||||
await Promise.all([
|
||||
this.page.waitForResponse(resp => resp.url().includes('/api/v1/list') && resp.status() === 200),
|
||||
this.listModalSaveButton.click()
|
||||
]);
|
||||
}
|
||||
|
||||
async delete() {
|
||||
await this.listItems.first().locator(".dropdown button").click();
|
||||
await this.listItems.first().locator(".menu .menu-item").filter({ hasText: "Delete" }).click();
|
||||
await Promise.all([
|
||||
this.page.waitForResponse(resp => resp.url().includes('/api/v1/list') && resp.status() === 200),
|
||||
this.confirmModalConfirmButton.click()
|
||||
]);
|
||||
}
|
||||
|
||||
async removeAll() {
|
||||
while ((await this.listItems.count()) > 0) {
|
||||
await this.delete();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
import { expect, test } from '@playwright/test';
|
||||
|
||||
test('index page has expected h1', async ({ page }) => {
|
||||
await page.goto('/');
|
||||
await expect(page.getByRole('heading', { name: 'Welcome to SvelteKit' })).toBeVisible();
|
||||
});
|
||||
Reference in New Issue
Block a user