chore: remove unused tests
Signed-off-by: Henrique Dias <mail@hacdias.com>pull/5522/head
parent
e9506c3eae
commit
f35b7c9d9d
|
|
@ -35,10 +35,5 @@ build/
|
||||||
/frontend/dist/*
|
/frontend/dist/*
|
||||||
!/frontend/dist/.gitkeep
|
!/frontend/dist/.gitkeep
|
||||||
|
|
||||||
# Playwright files
|
|
||||||
/frontend/test-results/
|
|
||||||
/frontend/playwright-report/
|
|
||||||
/frontend/playwright/.cache/
|
|
||||||
|
|
||||||
default.nix
|
default.nix
|
||||||
Dockerfile.dev
|
Dockerfile.dev
|
||||||
|
|
|
||||||
|
|
@ -14,8 +14,7 @@
|
||||||
"typecheck": "vue-tsc -p ./tsconfig.tsc.json --noEmit",
|
"typecheck": "vue-tsc -p ./tsconfig.tsc.json --noEmit",
|
||||||
"lint": "eslint src/",
|
"lint": "eslint src/",
|
||||||
"lint:fix": "eslint --fix src/",
|
"lint:fix": "eslint --fix src/",
|
||||||
"format": "prettier --write .",
|
"format": "prettier --write ."
|
||||||
"test": "playwright test"
|
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@chenfengyuan/vue-number-input": "^2.0.1",
|
"@chenfengyuan/vue-number-input": "^2.0.1",
|
||||||
|
|
@ -50,7 +49,6 @@
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@intlify/unplugin-vue-i18n": "^11.0.1",
|
"@intlify/unplugin-vue-i18n": "^11.0.1",
|
||||||
"@playwright/test": "^1.54.1",
|
|
||||||
"@tsconfig/node24": "^24.0.2",
|
"@tsconfig/node24": "^24.0.2",
|
||||||
"@types/lodash-es": "^4.17.12",
|
"@types/lodash-es": "^4.17.12",
|
||||||
"@types/node": "^24.10.1",
|
"@types/node": "^24.10.1",
|
||||||
|
|
|
||||||
|
|
@ -1,80 +0,0 @@
|
||||||
import { defineConfig, devices } from "@playwright/test";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Read environment variables from file.
|
|
||||||
* https://github.com/motdotla/dotenv
|
|
||||||
*/
|
|
||||||
// require('dotenv').config();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* See https://playwright.dev/docs/test-configuration.
|
|
||||||
*/
|
|
||||||
export default defineConfig({
|
|
||||||
testDir: "./tests",
|
|
||||||
/* Run tests in files in parallel */
|
|
||||||
fullyParallel: true,
|
|
||||||
/* Fail the build on CI if you accidentally left test.only in the source code. */
|
|
||||||
forbidOnly: !!process.env.CI,
|
|
||||||
/* Retry on CI only */
|
|
||||||
retries: process.env.CI ? 2 : 0,
|
|
||||||
/* Opt out of parallel tests on CI. */
|
|
||||||
workers: process.env.CI ? 1 : undefined,
|
|
||||||
/* Reporter to use. See https://playwright.dev/docs/test-reporters */
|
|
||||||
reporter: "html",
|
|
||||||
/* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
|
|
||||||
use: {
|
|
||||||
/* Base URL to use in actions like `await page.goto('/')`. */
|
|
||||||
baseURL: "http://127.0.0.1:5173",
|
|
||||||
|
|
||||||
/* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */
|
|
||||||
trace: "on-first-retry",
|
|
||||||
|
|
||||||
/* Set default locale to English (US) */
|
|
||||||
locale: "en-US",
|
|
||||||
},
|
|
||||||
|
|
||||||
/* Configure projects for major browsers */
|
|
||||||
projects: [
|
|
||||||
{
|
|
||||||
name: "chromium",
|
|
||||||
use: { ...devices["Desktop Chrome"] },
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
name: "firefox",
|
|
||||||
use: { ...devices["Desktop Firefox"] },
|
|
||||||
},
|
|
||||||
|
|
||||||
// {
|
|
||||||
// name: "webkit",
|
|
||||||
// use: { ...devices["Desktop Safari"] },
|
|
||||||
// },
|
|
||||||
|
|
||||||
/* Test against mobile viewports. */
|
|
||||||
// {
|
|
||||||
// name: 'Mobile Chrome',
|
|
||||||
// use: { ...devices['Pixel 5'] },
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// name: 'Mobile Safari',
|
|
||||||
// use: { ...devices['iPhone 12'] },
|
|
||||||
// },
|
|
||||||
|
|
||||||
/* Test against branded browsers. */
|
|
||||||
// {
|
|
||||||
// name: 'Microsoft Edge',
|
|
||||||
// use: { ...devices['Desktop Edge'], channel: 'msedge' },
|
|
||||||
// },
|
|
||||||
// {
|
|
||||||
// name: 'Google Chrome',
|
|
||||||
// use: { ...devices['Desktop Chrome'], channel: 'chrome' },
|
|
||||||
// },
|
|
||||||
],
|
|
||||||
|
|
||||||
/* Run your local dev server before starting the tests */
|
|
||||||
webServer: {
|
|
||||||
command: "npm run dev",
|
|
||||||
url: "http://127.0.0.1:5173",
|
|
||||||
reuseExistingServer: !process.env.CI,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
@ -99,9 +99,6 @@ importers:
|
||||||
'@intlify/unplugin-vue-i18n':
|
'@intlify/unplugin-vue-i18n':
|
||||||
specifier: ^11.0.1
|
specifier: ^11.0.1
|
||||||
version: 11.0.1(@vue/compiler-dom@3.5.24)(eslint@9.39.1)(rollup@4.52.5)(typescript@5.6.3)(vue-i18n@11.1.12(vue@3.5.24(typescript@5.6.3)))(vue@3.5.24(typescript@5.6.3))
|
version: 11.0.1(@vue/compiler-dom@3.5.24)(eslint@9.39.1)(rollup@4.52.5)(typescript@5.6.3)(vue-i18n@11.1.12(vue@3.5.24(typescript@5.6.3)))(vue@3.5.24(typescript@5.6.3))
|
||||||
'@playwright/test':
|
|
||||||
specifier: ^1.54.1
|
|
||||||
version: 1.56.1
|
|
||||||
'@tsconfig/node24':
|
'@tsconfig/node24':
|
||||||
specifier: ^24.0.2
|
specifier: ^24.0.2
|
||||||
version: 24.0.2
|
version: 24.0.2
|
||||||
|
|
@ -965,11 +962,6 @@ packages:
|
||||||
resolution: {integrity: sha512-QNqXyfVS2wm9hweSYD2O7F0G06uurj9kZ96TRQE5Y9hU7+tgdZwIkbAKc5Ocy1HxEY2kuDQa6cQ1WRs/O5LFKA==}
|
resolution: {integrity: sha512-QNqXyfVS2wm9hweSYD2O7F0G06uurj9kZ96TRQE5Y9hU7+tgdZwIkbAKc5Ocy1HxEY2kuDQa6cQ1WRs/O5LFKA==}
|
||||||
engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0}
|
engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0}
|
||||||
|
|
||||||
'@playwright/test@1.56.1':
|
|
||||||
resolution: {integrity: sha512-vSMYtL/zOcFpvJCW71Q/OEGQb7KYBPAdKh35WNSkaZA75JlAO8ED8UN6GUNTm3drWomcbcqRPFqQbLae8yBTdg==}
|
|
||||||
engines: {node: '>=18'}
|
|
||||||
hasBin: true
|
|
||||||
|
|
||||||
'@rolldown/pluginutils@1.0.0-beta.29':
|
'@rolldown/pluginutils@1.0.0-beta.29':
|
||||||
resolution: {integrity: sha512-NIJgOsMjbxAXvoGq/X0gD7VPMQ8j9g0BiDaNjVNVjvl+iKXxL3Jre0v31RmBYeLEmkbj2s02v8vFTbUXi5XS2Q==}
|
resolution: {integrity: sha512-NIJgOsMjbxAXvoGq/X0gD7VPMQ8j9g0BiDaNjVNVjvl+iKXxL3Jre0v31RmBYeLEmkbj2s02v8vFTbUXi5XS2Q==}
|
||||||
|
|
||||||
|
|
@ -1774,11 +1766,6 @@ packages:
|
||||||
fraction.js@5.3.4:
|
fraction.js@5.3.4:
|
||||||
resolution: {integrity: sha512-1X1NTtiJphryn/uLQz3whtY6jK3fTqoE3ohKs0tT+Ujr1W59oopxmoEh7Lu5p6vBaPbgoM0bzveAW4Qi5RyWDQ==}
|
resolution: {integrity: sha512-1X1NTtiJphryn/uLQz3whtY6jK3fTqoE3ohKs0tT+Ujr1W59oopxmoEh7Lu5p6vBaPbgoM0bzveAW4Qi5RyWDQ==}
|
||||||
|
|
||||||
fsevents@2.3.2:
|
|
||||||
resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==}
|
|
||||||
engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
|
|
||||||
os: [darwin]
|
|
||||||
|
|
||||||
fsevents@2.3.3:
|
fsevents@2.3.3:
|
||||||
resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==}
|
resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==}
|
||||||
engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
|
engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
|
||||||
|
|
@ -2124,16 +2111,6 @@ packages:
|
||||||
resolution: {integrity: sha512-afRERtHn54AlwaF2/+LFszyAANTCggGilmcmILUzEjvs3XgFZT+xE6+QWQcAGmu4xajy+Xtj7acLOPdx5/eXWQ==}
|
resolution: {integrity: sha512-afRERtHn54AlwaF2/+LFszyAANTCggGilmcmILUzEjvs3XgFZT+xE6+QWQcAGmu4xajy+Xtj7acLOPdx5/eXWQ==}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
|
||||||
playwright-core@1.56.1:
|
|
||||||
resolution: {integrity: sha512-hutraynyn31F+Bifme+Ps9Vq59hKuUCz7H1kDOcBs+2oGguKkWTU50bBWrtz34OUWmIwpBTWDxaRPXrIXkgvmQ==}
|
|
||||||
engines: {node: '>=18'}
|
|
||||||
hasBin: true
|
|
||||||
|
|
||||||
playwright@1.56.1:
|
|
||||||
resolution: {integrity: sha512-aFi5B0WovBHTEvpM3DzXTUaeN6eN0qWnTkKx4NQaH4Wvcmc153PdaY2UBdSYKaGYw+UyWXSVyxDUg5DoPEttjw==}
|
|
||||||
engines: {node: '>=18'}
|
|
||||||
hasBin: true
|
|
||||||
|
|
||||||
postcss-selector-parser@6.1.2:
|
postcss-selector-parser@6.1.2:
|
||||||
resolution: {integrity: sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==}
|
resolution: {integrity: sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==}
|
||||||
engines: {node: '>=4'}
|
engines: {node: '>=4'}
|
||||||
|
|
@ -3442,10 +3419,6 @@ snapshots:
|
||||||
|
|
||||||
'@pkgr/core@0.2.9': {}
|
'@pkgr/core@0.2.9': {}
|
||||||
|
|
||||||
'@playwright/test@1.56.1':
|
|
||||||
dependencies:
|
|
||||||
playwright: 1.56.1
|
|
||||||
|
|
||||||
'@rolldown/pluginutils@1.0.0-beta.29': {}
|
'@rolldown/pluginutils@1.0.0-beta.29': {}
|
||||||
|
|
||||||
'@rollup/pluginutils@5.3.0(rollup@4.52.5)':
|
'@rollup/pluginutils@5.3.0(rollup@4.52.5)':
|
||||||
|
|
@ -4333,9 +4306,6 @@ snapshots:
|
||||||
|
|
||||||
fraction.js@5.3.4: {}
|
fraction.js@5.3.4: {}
|
||||||
|
|
||||||
fsevents@2.3.2:
|
|
||||||
optional: true
|
|
||||||
|
|
||||||
fsevents@2.3.3:
|
fsevents@2.3.3:
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
|
|
@ -4629,14 +4599,6 @@ snapshots:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@babel/runtime': 7.28.4
|
'@babel/runtime': 7.28.4
|
||||||
|
|
||||||
playwright-core@1.56.1: {}
|
|
||||||
|
|
||||||
playwright@1.56.1:
|
|
||||||
dependencies:
|
|
||||||
playwright-core: 1.56.1
|
|
||||||
optionalDependencies:
|
|
||||||
fsevents: 2.3.2
|
|
||||||
|
|
||||||
postcss-selector-parser@6.1.2:
|
postcss-selector-parser@6.1.2:
|
||||||
dependencies:
|
dependencies:
|
||||||
cssesc: 3.0.0
|
cssesc: 3.0.0
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,4 @@
|
||||||
|
{
|
||||||
|
"status": "failed",
|
||||||
|
"failedTests": []
|
||||||
|
}
|
||||||
|
|
@ -1,489 +0,0 @@
|
||||||
import { test, expect, type Page } from "@playwright/test";
|
|
||||||
|
|
||||||
test.beforeEach(async ({ page }) => {
|
|
||||||
await page.goto("https://demo.playwright.dev/todomvc");
|
|
||||||
});
|
|
||||||
|
|
||||||
const TODO_ITEMS = [
|
|
||||||
"buy some cheese",
|
|
||||||
"feed the cat",
|
|
||||||
"book a doctors appointment",
|
|
||||||
];
|
|
||||||
|
|
||||||
test.describe("New Todo", () => {
|
|
||||||
test("should allow me to add todo items", async ({ page }) => {
|
|
||||||
// create a new todo locator
|
|
||||||
const newTodo = page.getByPlaceholder("What needs to be done?");
|
|
||||||
|
|
||||||
// Create 1st todo.
|
|
||||||
await newTodo.fill(TODO_ITEMS[0]);
|
|
||||||
await newTodo.press("Enter");
|
|
||||||
|
|
||||||
// Make sure the list only has one todo item.
|
|
||||||
await expect(page.getByTestId("todo-title")).toHaveText([TODO_ITEMS[0]]);
|
|
||||||
|
|
||||||
// Create 2nd todo.
|
|
||||||
await newTodo.fill(TODO_ITEMS[1]);
|
|
||||||
await newTodo.press("Enter");
|
|
||||||
|
|
||||||
// Make sure the list now has two todo items.
|
|
||||||
await expect(page.getByTestId("todo-title")).toHaveText([
|
|
||||||
TODO_ITEMS[0],
|
|
||||||
TODO_ITEMS[1],
|
|
||||||
]);
|
|
||||||
|
|
||||||
await checkNumberOfTodosInLocalStorage(page, 2);
|
|
||||||
});
|
|
||||||
|
|
||||||
test("should clear text input field when an item is added", async ({
|
|
||||||
page,
|
|
||||||
}) => {
|
|
||||||
// create a new todo locator
|
|
||||||
const newTodo = page.getByPlaceholder("What needs to be done?");
|
|
||||||
|
|
||||||
// Create one todo item.
|
|
||||||
await newTodo.fill(TODO_ITEMS[0]);
|
|
||||||
await newTodo.press("Enter");
|
|
||||||
|
|
||||||
// Check that input is empty.
|
|
||||||
await expect(newTodo).toBeEmpty();
|
|
||||||
await checkNumberOfTodosInLocalStorage(page, 1);
|
|
||||||
});
|
|
||||||
|
|
||||||
test("should append new items to the bottom of the list", async ({
|
|
||||||
page,
|
|
||||||
}) => {
|
|
||||||
// Create 3 items.
|
|
||||||
await createDefaultTodos(page);
|
|
||||||
|
|
||||||
// create a todo count locator
|
|
||||||
const todoCount = page.getByTestId("todo-count");
|
|
||||||
|
|
||||||
// Check test using different methods.
|
|
||||||
await expect(page.getByText("3 items left")).toBeVisible();
|
|
||||||
await expect(todoCount).toHaveText("3 items left");
|
|
||||||
await expect(todoCount).toContainText("3");
|
|
||||||
await expect(todoCount).toHaveText(/3/);
|
|
||||||
|
|
||||||
// Check all items in one call.
|
|
||||||
await expect(page.getByTestId("todo-title")).toHaveText(TODO_ITEMS);
|
|
||||||
await checkNumberOfTodosInLocalStorage(page, 3);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
test.describe("Mark all as completed", () => {
|
|
||||||
test.beforeEach(async ({ page }) => {
|
|
||||||
await createDefaultTodos(page);
|
|
||||||
await checkNumberOfTodosInLocalStorage(page, 3);
|
|
||||||
});
|
|
||||||
|
|
||||||
test.afterEach(async ({ page }) => {
|
|
||||||
await checkNumberOfTodosInLocalStorage(page, 3);
|
|
||||||
});
|
|
||||||
|
|
||||||
test("should allow me to mark all items as completed", async ({ page }) => {
|
|
||||||
// Complete all todos.
|
|
||||||
await page.getByLabel("Mark all as complete").check();
|
|
||||||
|
|
||||||
// Ensure all todos have 'completed' class.
|
|
||||||
await expect(page.getByTestId("todo-item")).toHaveClass([
|
|
||||||
"completed",
|
|
||||||
"completed",
|
|
||||||
"completed",
|
|
||||||
]);
|
|
||||||
await checkNumberOfCompletedTodosInLocalStorage(page, 3);
|
|
||||||
});
|
|
||||||
|
|
||||||
test("should allow me to clear the complete state of all items", async ({
|
|
||||||
page,
|
|
||||||
}) => {
|
|
||||||
const toggleAll = page.getByLabel("Mark all as complete");
|
|
||||||
// Check and then immediately uncheck.
|
|
||||||
await toggleAll.check();
|
|
||||||
await toggleAll.uncheck();
|
|
||||||
|
|
||||||
// Should be no completed classes.
|
|
||||||
await expect(page.getByTestId("todo-item")).toHaveClass(["", "", ""]);
|
|
||||||
});
|
|
||||||
|
|
||||||
test("complete all checkbox should update state when items are completed / cleared", async ({
|
|
||||||
page,
|
|
||||||
}) => {
|
|
||||||
const toggleAll = page.getByLabel("Mark all as complete");
|
|
||||||
await toggleAll.check();
|
|
||||||
await expect(toggleAll).toBeChecked();
|
|
||||||
await checkNumberOfCompletedTodosInLocalStorage(page, 3);
|
|
||||||
|
|
||||||
// Uncheck first todo.
|
|
||||||
const firstTodo = page.getByTestId("todo-item").nth(0);
|
|
||||||
await firstTodo.getByRole("checkbox").uncheck();
|
|
||||||
|
|
||||||
// Reuse toggleAll locator and make sure its not checked.
|
|
||||||
await expect(toggleAll).not.toBeChecked();
|
|
||||||
|
|
||||||
await firstTodo.getByRole("checkbox").check();
|
|
||||||
await checkNumberOfCompletedTodosInLocalStorage(page, 3);
|
|
||||||
|
|
||||||
// Assert the toggle all is checked again.
|
|
||||||
await expect(toggleAll).toBeChecked();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
test.describe("Item", () => {
|
|
||||||
test("should allow me to mark items as complete", async ({ page }) => {
|
|
||||||
// create a new todo locator
|
|
||||||
const newTodo = page.getByPlaceholder("What needs to be done?");
|
|
||||||
|
|
||||||
// Create two items.
|
|
||||||
for (const item of TODO_ITEMS.slice(0, 2)) {
|
|
||||||
await newTodo.fill(item);
|
|
||||||
await newTodo.press("Enter");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check first item.
|
|
||||||
const firstTodo = page.getByTestId("todo-item").nth(0);
|
|
||||||
await firstTodo.getByRole("checkbox").check();
|
|
||||||
await expect(firstTodo).toHaveClass("completed");
|
|
||||||
|
|
||||||
// Check second item.
|
|
||||||
const secondTodo = page.getByTestId("todo-item").nth(1);
|
|
||||||
await expect(secondTodo).not.toHaveClass("completed");
|
|
||||||
await secondTodo.getByRole("checkbox").check();
|
|
||||||
|
|
||||||
// Assert completed class.
|
|
||||||
await expect(firstTodo).toHaveClass("completed");
|
|
||||||
await expect(secondTodo).toHaveClass("completed");
|
|
||||||
});
|
|
||||||
|
|
||||||
test("should allow me to un-mark items as complete", async ({ page }) => {
|
|
||||||
// create a new todo locator
|
|
||||||
const newTodo = page.getByPlaceholder("What needs to be done?");
|
|
||||||
|
|
||||||
// Create two items.
|
|
||||||
for (const item of TODO_ITEMS.slice(0, 2)) {
|
|
||||||
await newTodo.fill(item);
|
|
||||||
await newTodo.press("Enter");
|
|
||||||
}
|
|
||||||
|
|
||||||
const firstTodo = page.getByTestId("todo-item").nth(0);
|
|
||||||
const secondTodo = page.getByTestId("todo-item").nth(1);
|
|
||||||
const firstTodoCheckbox = firstTodo.getByRole("checkbox");
|
|
||||||
|
|
||||||
await firstTodoCheckbox.check();
|
|
||||||
await expect(firstTodo).toHaveClass("completed");
|
|
||||||
await expect(secondTodo).not.toHaveClass("completed");
|
|
||||||
await checkNumberOfCompletedTodosInLocalStorage(page, 1);
|
|
||||||
|
|
||||||
await firstTodoCheckbox.uncheck();
|
|
||||||
await expect(firstTodo).not.toHaveClass("completed");
|
|
||||||
await expect(secondTodo).not.toHaveClass("completed");
|
|
||||||
await checkNumberOfCompletedTodosInLocalStorage(page, 0);
|
|
||||||
});
|
|
||||||
|
|
||||||
test("should allow me to edit an item", async ({ page }) => {
|
|
||||||
await createDefaultTodos(page);
|
|
||||||
|
|
||||||
const todoItems = page.getByTestId("todo-item");
|
|
||||||
const secondTodo = todoItems.nth(1);
|
|
||||||
await secondTodo.dblclick();
|
|
||||||
await expect(secondTodo.getByRole("textbox", { name: "Edit" })).toHaveValue(
|
|
||||||
TODO_ITEMS[1]
|
|
||||||
);
|
|
||||||
await secondTodo
|
|
||||||
.getByRole("textbox", { name: "Edit" })
|
|
||||||
.fill("buy some sausages");
|
|
||||||
await secondTodo.getByRole("textbox", { name: "Edit" }).press("Enter");
|
|
||||||
|
|
||||||
// Explicitly assert the new text value.
|
|
||||||
await expect(todoItems).toHaveText([
|
|
||||||
TODO_ITEMS[0],
|
|
||||||
"buy some sausages",
|
|
||||||
TODO_ITEMS[2],
|
|
||||||
]);
|
|
||||||
await checkTodosInLocalStorage(page, "buy some sausages");
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
test.describe("Editing", () => {
|
|
||||||
test.beforeEach(async ({ page }) => {
|
|
||||||
await createDefaultTodos(page);
|
|
||||||
await checkNumberOfTodosInLocalStorage(page, 3);
|
|
||||||
});
|
|
||||||
|
|
||||||
test("should hide other controls when editing", async ({ page }) => {
|
|
||||||
const todoItem = page.getByTestId("todo-item").nth(1);
|
|
||||||
await todoItem.dblclick();
|
|
||||||
await expect(todoItem.getByRole("checkbox")).not.toBeVisible();
|
|
||||||
await expect(
|
|
||||||
todoItem.locator("label", {
|
|
||||||
hasText: TODO_ITEMS[1],
|
|
||||||
})
|
|
||||||
).not.toBeVisible();
|
|
||||||
await checkNumberOfTodosInLocalStorage(page, 3);
|
|
||||||
});
|
|
||||||
|
|
||||||
test("should save edits on blur", async ({ page }) => {
|
|
||||||
const todoItems = page.getByTestId("todo-item");
|
|
||||||
await todoItems.nth(1).dblclick();
|
|
||||||
await todoItems
|
|
||||||
.nth(1)
|
|
||||||
.getByRole("textbox", { name: "Edit" })
|
|
||||||
.fill("buy some sausages");
|
|
||||||
await todoItems
|
|
||||||
.nth(1)
|
|
||||||
.getByRole("textbox", { name: "Edit" })
|
|
||||||
.dispatchEvent("blur");
|
|
||||||
|
|
||||||
await expect(todoItems).toHaveText([
|
|
||||||
TODO_ITEMS[0],
|
|
||||||
"buy some sausages",
|
|
||||||
TODO_ITEMS[2],
|
|
||||||
]);
|
|
||||||
await checkTodosInLocalStorage(page, "buy some sausages");
|
|
||||||
});
|
|
||||||
|
|
||||||
test("should trim entered text", async ({ page }) => {
|
|
||||||
const todoItems = page.getByTestId("todo-item");
|
|
||||||
await todoItems.nth(1).dblclick();
|
|
||||||
await todoItems
|
|
||||||
.nth(1)
|
|
||||||
.getByRole("textbox", { name: "Edit" })
|
|
||||||
.fill(" buy some sausages ");
|
|
||||||
await todoItems
|
|
||||||
.nth(1)
|
|
||||||
.getByRole("textbox", { name: "Edit" })
|
|
||||||
.press("Enter");
|
|
||||||
|
|
||||||
await expect(todoItems).toHaveText([
|
|
||||||
TODO_ITEMS[0],
|
|
||||||
"buy some sausages",
|
|
||||||
TODO_ITEMS[2],
|
|
||||||
]);
|
|
||||||
await checkTodosInLocalStorage(page, "buy some sausages");
|
|
||||||
});
|
|
||||||
|
|
||||||
test("should remove the item if an empty text string was entered", async ({
|
|
||||||
page,
|
|
||||||
}) => {
|
|
||||||
const todoItems = page.getByTestId("todo-item");
|
|
||||||
await todoItems.nth(1).dblclick();
|
|
||||||
await todoItems.nth(1).getByRole("textbox", { name: "Edit" }).fill("");
|
|
||||||
await todoItems
|
|
||||||
.nth(1)
|
|
||||||
.getByRole("textbox", { name: "Edit" })
|
|
||||||
.press("Enter");
|
|
||||||
|
|
||||||
await expect(todoItems).toHaveText([TODO_ITEMS[0], TODO_ITEMS[2]]);
|
|
||||||
});
|
|
||||||
|
|
||||||
test("should cancel edits on escape", async ({ page }) => {
|
|
||||||
const todoItems = page.getByTestId("todo-item");
|
|
||||||
await todoItems.nth(1).dblclick();
|
|
||||||
await todoItems
|
|
||||||
.nth(1)
|
|
||||||
.getByRole("textbox", { name: "Edit" })
|
|
||||||
.fill("buy some sausages");
|
|
||||||
await todoItems
|
|
||||||
.nth(1)
|
|
||||||
.getByRole("textbox", { name: "Edit" })
|
|
||||||
.press("Escape");
|
|
||||||
await expect(todoItems).toHaveText(TODO_ITEMS);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
test.describe("Counter", () => {
|
|
||||||
test("should display the current number of todo items", async ({ page }) => {
|
|
||||||
// create a new todo locator
|
|
||||||
const newTodo = page.getByPlaceholder("What needs to be done?");
|
|
||||||
|
|
||||||
// create a todo count locator
|
|
||||||
const todoCount = page.getByTestId("todo-count");
|
|
||||||
|
|
||||||
await newTodo.fill(TODO_ITEMS[0]);
|
|
||||||
await newTodo.press("Enter");
|
|
||||||
|
|
||||||
await expect(todoCount).toContainText("1");
|
|
||||||
|
|
||||||
await newTodo.fill(TODO_ITEMS[1]);
|
|
||||||
await newTodo.press("Enter");
|
|
||||||
await expect(todoCount).toContainText("2");
|
|
||||||
|
|
||||||
await checkNumberOfTodosInLocalStorage(page, 2);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
test.describe("Clear completed button", () => {
|
|
||||||
test.beforeEach(async ({ page }) => {
|
|
||||||
await createDefaultTodos(page);
|
|
||||||
});
|
|
||||||
|
|
||||||
test("should display the correct text", async ({ page }) => {
|
|
||||||
await page.locator(".todo-list li .toggle").first().check();
|
|
||||||
await expect(
|
|
||||||
page.getByRole("button", { name: "Clear completed" })
|
|
||||||
).toBeVisible();
|
|
||||||
});
|
|
||||||
|
|
||||||
test("should remove completed items when clicked", async ({ page }) => {
|
|
||||||
const todoItems = page.getByTestId("todo-item");
|
|
||||||
await todoItems.nth(1).getByRole("checkbox").check();
|
|
||||||
await page.getByRole("button", { name: "Clear completed" }).click();
|
|
||||||
await expect(todoItems).toHaveCount(2);
|
|
||||||
await expect(todoItems).toHaveText([TODO_ITEMS[0], TODO_ITEMS[2]]);
|
|
||||||
});
|
|
||||||
|
|
||||||
test("should be hidden when there are no items that are completed", async ({
|
|
||||||
page,
|
|
||||||
}) => {
|
|
||||||
await page.locator(".todo-list li .toggle").first().check();
|
|
||||||
await page.getByRole("button", { name: "Clear completed" }).click();
|
|
||||||
await expect(
|
|
||||||
page.getByRole("button", { name: "Clear completed" })
|
|
||||||
).toBeHidden();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
test.describe("Persistence", () => {
|
|
||||||
test("should persist its data", async ({ page }) => {
|
|
||||||
// create a new todo locator
|
|
||||||
const newTodo = page.getByPlaceholder("What needs to be done?");
|
|
||||||
|
|
||||||
for (const item of TODO_ITEMS.slice(0, 2)) {
|
|
||||||
await newTodo.fill(item);
|
|
||||||
await newTodo.press("Enter");
|
|
||||||
}
|
|
||||||
|
|
||||||
const todoItems = page.getByTestId("todo-item");
|
|
||||||
const firstTodoCheck = todoItems.nth(0).getByRole("checkbox");
|
|
||||||
await firstTodoCheck.check();
|
|
||||||
await expect(todoItems).toHaveText([TODO_ITEMS[0], TODO_ITEMS[1]]);
|
|
||||||
await expect(firstTodoCheck).toBeChecked();
|
|
||||||
await expect(todoItems).toHaveClass(["completed", ""]);
|
|
||||||
|
|
||||||
// Ensure there is 1 completed item.
|
|
||||||
await checkNumberOfCompletedTodosInLocalStorage(page, 1);
|
|
||||||
|
|
||||||
// Now reload.
|
|
||||||
await page.reload();
|
|
||||||
await expect(todoItems).toHaveText([TODO_ITEMS[0], TODO_ITEMS[1]]);
|
|
||||||
await expect(firstTodoCheck).toBeChecked();
|
|
||||||
await expect(todoItems).toHaveClass(["completed", ""]);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
test.describe("Routing", () => {
|
|
||||||
test.beforeEach(async ({ page }) => {
|
|
||||||
await createDefaultTodos(page);
|
|
||||||
// make sure the app had a chance to save updated todos in storage
|
|
||||||
// before navigating to a new view, otherwise the items can get lost :(
|
|
||||||
// in some frameworks like Durandal
|
|
||||||
await checkTodosInLocalStorage(page, TODO_ITEMS[0]);
|
|
||||||
});
|
|
||||||
|
|
||||||
test("should allow me to display active items", async ({ page }) => {
|
|
||||||
const todoItem = page.getByTestId("todo-item");
|
|
||||||
await page.getByTestId("todo-item").nth(1).getByRole("checkbox").check();
|
|
||||||
|
|
||||||
await checkNumberOfCompletedTodosInLocalStorage(page, 1);
|
|
||||||
await page.getByRole("link", { name: "Active" }).click();
|
|
||||||
await expect(todoItem).toHaveCount(2);
|
|
||||||
await expect(todoItem).toHaveText([TODO_ITEMS[0], TODO_ITEMS[2]]);
|
|
||||||
});
|
|
||||||
|
|
||||||
test("should respect the back button", async ({ page }) => {
|
|
||||||
const todoItem = page.getByTestId("todo-item");
|
|
||||||
await page.getByTestId("todo-item").nth(1).getByRole("checkbox").check();
|
|
||||||
|
|
||||||
await checkNumberOfCompletedTodosInLocalStorage(page, 1);
|
|
||||||
|
|
||||||
await test.step("Showing all items", async () => {
|
|
||||||
await page.getByRole("link", { name: "All" }).click();
|
|
||||||
await expect(todoItem).toHaveCount(3);
|
|
||||||
});
|
|
||||||
|
|
||||||
await test.step("Showing active items", async () => {
|
|
||||||
await page.getByRole("link", { name: "Active" }).click();
|
|
||||||
});
|
|
||||||
|
|
||||||
await test.step("Showing completed items", async () => {
|
|
||||||
await page.getByRole("link", { name: "Completed" }).click();
|
|
||||||
});
|
|
||||||
|
|
||||||
await expect(todoItem).toHaveCount(1);
|
|
||||||
await page.goBack();
|
|
||||||
await expect(todoItem).toHaveCount(2);
|
|
||||||
await page.goBack();
|
|
||||||
await expect(todoItem).toHaveCount(3);
|
|
||||||
});
|
|
||||||
|
|
||||||
test("should allow me to display completed items", async ({ page }) => {
|
|
||||||
await page.getByTestId("todo-item").nth(1).getByRole("checkbox").check();
|
|
||||||
await checkNumberOfCompletedTodosInLocalStorage(page, 1);
|
|
||||||
await page.getByRole("link", { name: "Completed" }).click();
|
|
||||||
await expect(page.getByTestId("todo-item")).toHaveCount(1);
|
|
||||||
});
|
|
||||||
|
|
||||||
test("should allow me to display all items", async ({ page }) => {
|
|
||||||
await page.getByTestId("todo-item").nth(1).getByRole("checkbox").check();
|
|
||||||
await checkNumberOfCompletedTodosInLocalStorage(page, 1);
|
|
||||||
await page.getByRole("link", { name: "Active" }).click();
|
|
||||||
await page.getByRole("link", { name: "Completed" }).click();
|
|
||||||
await page.getByRole("link", { name: "All" }).click();
|
|
||||||
await expect(page.getByTestId("todo-item")).toHaveCount(3);
|
|
||||||
});
|
|
||||||
|
|
||||||
test("should highlight the currently applied filter", async ({ page }) => {
|
|
||||||
await expect(page.getByRole("link", { name: "All" })).toHaveClass(
|
|
||||||
"selected"
|
|
||||||
);
|
|
||||||
|
|
||||||
//create locators for active and completed links
|
|
||||||
const activeLink = page.getByRole("link", { name: "Active" });
|
|
||||||
const completedLink = page.getByRole("link", { name: "Completed" });
|
|
||||||
await activeLink.click();
|
|
||||||
|
|
||||||
// Page change - active items.
|
|
||||||
await expect(activeLink).toHaveClass("selected");
|
|
||||||
await completedLink.click();
|
|
||||||
|
|
||||||
// Page change - completed items.
|
|
||||||
await expect(completedLink).toHaveClass("selected");
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
async function createDefaultTodos(page: Page) {
|
|
||||||
// create a new todo locator
|
|
||||||
const newTodo = page.getByPlaceholder("What needs to be done?");
|
|
||||||
|
|
||||||
for (const item of TODO_ITEMS) {
|
|
||||||
await newTodo.fill(item);
|
|
||||||
await newTodo.press("Enter");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async function checkNumberOfTodosInLocalStorage(page: Page, expected: number) {
|
|
||||||
return await page.waitForFunction((e) => {
|
|
||||||
return JSON.parse(localStorage["react-todos"]).length === e;
|
|
||||||
}, expected);
|
|
||||||
}
|
|
||||||
|
|
||||||
async function checkNumberOfCompletedTodosInLocalStorage(
|
|
||||||
page: Page,
|
|
||||||
expected: number
|
|
||||||
) {
|
|
||||||
return await page.waitForFunction((e) => {
|
|
||||||
return (
|
|
||||||
JSON.parse(localStorage["react-todos"]).filter(
|
|
||||||
(todo: any) => todo.completed
|
|
||||||
).length === e
|
|
||||||
);
|
|
||||||
}, expected);
|
|
||||||
}
|
|
||||||
|
|
||||||
async function checkTodosInLocalStorage(page: Page, title: string) {
|
|
||||||
return await page.waitForFunction((t) => {
|
|
||||||
return JSON.parse(localStorage["react-todos"])
|
|
||||||
.map((todo: any) => todo.title)
|
|
||||||
.includes(t);
|
|
||||||
}, title);
|
|
||||||
}
|
|
||||||
|
|
@ -1,32 +0,0 @@
|
||||||
import { test, expect } from "./fixtures/auth";
|
|
||||||
|
|
||||||
test("redirect to login", async ({ page }) => {
|
|
||||||
await page.goto("/");
|
|
||||||
await expect(page).toHaveURL(/\/login/);
|
|
||||||
|
|
||||||
await page.goto("/files/");
|
|
||||||
await expect(page).toHaveURL(/\/login\?redirect=\/files\//);
|
|
||||||
});
|
|
||||||
|
|
||||||
test("login and logout", async ({ authPage, page, context }) => {
|
|
||||||
await authPage.goto();
|
|
||||||
await expect(page).toHaveTitle(/Login - File Browser$/);
|
|
||||||
|
|
||||||
await authPage.loginAs("fake", "fake");
|
|
||||||
await expect(authPage.wrongCredentials).toBeVisible();
|
|
||||||
|
|
||||||
await authPage.loginAs();
|
|
||||||
await expect(authPage.wrongCredentials).toBeHidden();
|
|
||||||
// await page.waitForURL("**/files/", { timeout: 5000 });
|
|
||||||
await expect(page).toHaveTitle(/.*Files - File Browser$/);
|
|
||||||
|
|
||||||
let cookies = await context.cookies();
|
|
||||||
expect(cookies.find((c) => c.name == "auth")?.value).toBeDefined();
|
|
||||||
|
|
||||||
await authPage.logout();
|
|
||||||
// await page.waitForURL("**/login", { timeout: 5000 });
|
|
||||||
await expect(page).toHaveTitle(/Login - File Browser$/);
|
|
||||||
|
|
||||||
cookies = await context.cookies();
|
|
||||||
expect(cookies.find((c) => c.name == "auth")?.value).toBeUndefined();
|
|
||||||
});
|
|
||||||
|
|
@ -1,40 +0,0 @@
|
||||||
import {
|
|
||||||
type Page,
|
|
||||||
type Locator,
|
|
||||||
test as base,
|
|
||||||
expect,
|
|
||||||
} from "@playwright/test";
|
|
||||||
|
|
||||||
export class AuthPage {
|
|
||||||
public readonly wrongCredentials: Locator;
|
|
||||||
|
|
||||||
constructor(public readonly page: Page) {
|
|
||||||
this.wrongCredentials = this.page.locator("div.wrong");
|
|
||||||
}
|
|
||||||
|
|
||||||
async goto() {
|
|
||||||
await this.page.goto("/login");
|
|
||||||
}
|
|
||||||
|
|
||||||
async loginAs(username = "admin", password = "admin") {
|
|
||||||
await this.page.getByPlaceholder("Username").fill(username);
|
|
||||||
await this.page.getByPlaceholder("Password").fill(password);
|
|
||||||
await this.page.getByRole("button", { name: "Login" }).click();
|
|
||||||
}
|
|
||||||
|
|
||||||
async logout() {
|
|
||||||
await this.page.getByRole("button", { name: "Logout" }).click();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const test = base.extend<{ authPage: AuthPage }>({
|
|
||||||
authPage: async ({ page }, use) => {
|
|
||||||
const authPage = new AuthPage(page);
|
|
||||||
await authPage.goto();
|
|
||||||
await authPage.loginAs();
|
|
||||||
await use(authPage);
|
|
||||||
// await authPage.logout();
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
export { test, expect };
|
|
||||||
|
|
@ -1,61 +0,0 @@
|
||||||
import {
|
|
||||||
type Locator,
|
|
||||||
type Page,
|
|
||||||
test as base,
|
|
||||||
expect,
|
|
||||||
} from "@playwright/test";
|
|
||||||
import { AuthPage } from "./auth";
|
|
||||||
|
|
||||||
type SettingsType = "profile" | "shares" | "global" | "users";
|
|
||||||
|
|
||||||
export class SettingsPage {
|
|
||||||
public readonly hideDotfiles: Locator; // checkbox
|
|
||||||
public readonly singleClick: Locator; // checkbox
|
|
||||||
public readonly dateFormat: Locator; // checkbox
|
|
||||||
private readonly languages: Locator; // selection
|
|
||||||
private readonly submitProfile: Locator; // submit
|
|
||||||
private readonly submitPassword: Locator; // submit
|
|
||||||
|
|
||||||
constructor(public readonly page: Page) {
|
|
||||||
this.hideDotfiles = this.page.locator('input[name="hideDotfiles"]');
|
|
||||||
this.singleClick = this.page.locator('input[name="singleClick"]');
|
|
||||||
this.dateFormat = this.page.locator('input[name="dateFormat"]');
|
|
||||||
this.languages = this.page.locator('select[name="selectLanguage"]');
|
|
||||||
this.submitProfile = this.page.locator('input[name="submitProfile"]');
|
|
||||||
this.submitPassword = this.page.locator('input[name="submitPassword"]');
|
|
||||||
}
|
|
||||||
|
|
||||||
async goto(type: SettingsType = "profile") {
|
|
||||||
await this.page.goto(`/settings/${type}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
async setLanguage(locale: string = "en") {
|
|
||||||
await this.languages.selectOption(locale);
|
|
||||||
}
|
|
||||||
|
|
||||||
async saveProfile() {
|
|
||||||
await this.submitProfile.click();
|
|
||||||
}
|
|
||||||
|
|
||||||
async savePassword() {
|
|
||||||
await this.submitPassword.click();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const test = base.extend<{ settingsPage: SettingsPage }>({
|
|
||||||
page: async ({ page }, use) => {
|
|
||||||
// Sign in with our account.
|
|
||||||
const authPage = new AuthPage(page);
|
|
||||||
await authPage.goto();
|
|
||||||
await authPage.loginAs();
|
|
||||||
await expect(page).toHaveTitle(/.*Files - File Browser$/);
|
|
||||||
// Use signed-in page in the test.
|
|
||||||
await use(page);
|
|
||||||
},
|
|
||||||
settingsPage: async ({ page }, use) => {
|
|
||||||
const settingsPage = new SettingsPage(page);
|
|
||||||
await use(settingsPage);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
export { test, expect };
|
|
||||||
|
|
@ -1,20 +0,0 @@
|
||||||
//classes: Vue-Toastification__toast Vue-Toastification__toast--success bottom-center
|
|
||||||
import { type Page, type Locator, expect } from "@playwright/test";
|
|
||||||
|
|
||||||
export class Toast {
|
|
||||||
private readonly success: Locator;
|
|
||||||
private readonly error: Locator;
|
|
||||||
|
|
||||||
constructor(public readonly page: Page) {
|
|
||||||
this.success = this.page.locator("div.Vue-Toastification__toast--success");
|
|
||||||
this.error = this.page.locator("div.Vue-Toastification__toast--error");
|
|
||||||
}
|
|
||||||
|
|
||||||
async isSuccess() {
|
|
||||||
await expect(this.success).toBeVisible();
|
|
||||||
}
|
|
||||||
|
|
||||||
async isError() {
|
|
||||||
await expect(this.error).toBeVisible();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,46 +0,0 @@
|
||||||
import { test, expect } from "./fixtures/settings";
|
|
||||||
import { Toast } from "./fixtures/toast";
|
|
||||||
|
|
||||||
// test.describe("profile settings", () => {
|
|
||||||
test("settings button", async ({ page }) => {
|
|
||||||
const button = page.getByLabel("Settings", { exact: true });
|
|
||||||
await expect(button).toBeVisible();
|
|
||||||
await button.click();
|
|
||||||
await expect(page).toHaveTitle(/^Profile Settings/);
|
|
||||||
await expect(
|
|
||||||
page.getByRole("heading", { name: "Profile Settings" })
|
|
||||||
).toBeVisible();
|
|
||||||
});
|
|
||||||
|
|
||||||
test("set locale", async ({ settingsPage, page }) => {
|
|
||||||
const toast = new Toast(page);
|
|
||||||
|
|
||||||
await settingsPage.goto("profile");
|
|
||||||
await expect(page).toHaveTitle(/^Profile Settings/);
|
|
||||||
// await settingsPage.saveProfile();
|
|
||||||
// await toast.isSuccess();
|
|
||||||
// await expect(
|
|
||||||
// page.getByText("Settings updated!", { exact: true })
|
|
||||||
// ).toBeVisible();
|
|
||||||
|
|
||||||
await settingsPage.setLanguage("hu");
|
|
||||||
await settingsPage.saveProfile();
|
|
||||||
await toast.isSuccess();
|
|
||||||
await expect(
|
|
||||||
page.getByText("Beállítások frissítve!", { exact: true })
|
|
||||||
).toBeVisible();
|
|
||||||
await expect(
|
|
||||||
page.getByRole("heading", { name: "Profilbeállítások" })
|
|
||||||
).toBeVisible();
|
|
||||||
|
|
||||||
await settingsPage.setLanguage("en");
|
|
||||||
await settingsPage.saveProfile();
|
|
||||||
await toast.isSuccess();
|
|
||||||
await expect(
|
|
||||||
page.getByText("Settings updated!", { exact: true })
|
|
||||||
).toBeVisible();
|
|
||||||
await expect(
|
|
||||||
page.getByRole("heading", { name: "Profile Settings" })
|
|
||||||
).toBeVisible();
|
|
||||||
});
|
|
||||||
// });
|
|
||||||
|
|
@ -4,8 +4,7 @@
|
||||||
"vite.config.*",
|
"vite.config.*",
|
||||||
"vitest.config.*",
|
"vitest.config.*",
|
||||||
"cypress.config.*",
|
"cypress.config.*",
|
||||||
"nightwatch.conf.*",
|
"nightwatch.conf.*"
|
||||||
"playwright.config.*"
|
|
||||||
],
|
],
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"composite": true,
|
"composite": true,
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue