Add Playwright configuration and update codebase
The commit introduces Playwright configuration for End-to-End testing and modifies several files to optimize the project's structure. It also modifies the middleware to interact with Next.js and fix URL creation. Changes in database types were made to refine their structure.
This commit is contained in:
41
.github/workflows/workflow.yml
vendored
Normal file
41
.github/workflows/workflow.yml
vendored
Normal file
@@ -0,0 +1,41 @@
|
||||
name: Workflow
|
||||
on:
|
||||
push:
|
||||
branches: [ main ]
|
||||
pull_request:
|
||||
branches: [ main ]
|
||||
jobs:
|
||||
typescript:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: lts/*
|
||||
- name: Install dependencies
|
||||
run: npm install -g pnpm && pnpm install
|
||||
- name: Typecheck
|
||||
run: pnpm run typecheck
|
||||
- name: Lint
|
||||
run: pnpm run lint
|
||||
|
||||
test:
|
||||
timeout-minutes: 60
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: lts/*
|
||||
- name: Install dependencies
|
||||
run: npm install -g pnpm && pnpm install
|
||||
- name: Install Playwright Browsers
|
||||
run: pnpm exec playwright install --with-deps
|
||||
- name: Run Playwright tests
|
||||
run: pnpm run test
|
||||
- uses: actions/upload-artifact@v4
|
||||
if: always()
|
||||
with:
|
||||
name: playwright-report
|
||||
path: playwright-report/
|
||||
retention-days: 30
|
||||
5
apps/e2e/.gitignore
vendored
Normal file
5
apps/e2e/.gitignore
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
node_modules/
|
||||
/test-results/
|
||||
/playwright-report/
|
||||
/blob-report/
|
||||
/playwright/.cache/
|
||||
19
apps/e2e/package.json
Normal file
19
apps/e2e/package.json
Normal file
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"name": "web-e2e",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"report": "playwright show-report",
|
||||
"test": "playwright test",
|
||||
"test:ui": "playwright test --ui"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"devDependencies": {
|
||||
"@playwright/test": "^1.43.0",
|
||||
"@types/node": "^20.12.7",
|
||||
"node-html-parser": "^6.1.13"
|
||||
}
|
||||
}
|
||||
66
apps/e2e/playwright.config.ts
Normal file
66
apps/e2e/playwright.config.ts
Normal file
@@ -0,0 +1,66 @@
|
||||
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://localhost:3000',
|
||||
|
||||
/* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */
|
||||
trace: 'on-first-retry',
|
||||
},
|
||||
|
||||
/* Configure projects for major browsers */
|
||||
projects: [
|
||||
{
|
||||
name: 'chromium',
|
||||
use: { ...devices['Desktop Chrome'] },
|
||||
},
|
||||
/* 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 start',
|
||||
// url: 'http://127.0.0.1:3000',
|
||||
// reuseExistingServer: !process.env.CI,
|
||||
// },
|
||||
});
|
||||
54
apps/e2e/tests/authentication/auth.po.ts
Normal file
54
apps/e2e/tests/authentication/auth.po.ts
Normal file
@@ -0,0 +1,54 @@
|
||||
import { Page } from '@playwright/test';
|
||||
import { Mailbox } from '../utils/mailbox';
|
||||
|
||||
export class AuthPageObject {
|
||||
private readonly page: Page;
|
||||
private readonly mailbox: Mailbox;
|
||||
|
||||
constructor(page: Page) {
|
||||
this.page = page;
|
||||
this.mailbox = new Mailbox(page);
|
||||
}
|
||||
|
||||
goToSignIn() {
|
||||
return this.page.goto('/auth/sign-in');
|
||||
}
|
||||
|
||||
goToSignUp() {
|
||||
return this.page.goto('/auth/sign-up');
|
||||
}
|
||||
|
||||
async signIn(params: {
|
||||
email: string,
|
||||
password: string
|
||||
}) {
|
||||
await this.page.locator('input[name="email"]').clear();
|
||||
|
||||
await this.page.fill('input[name="email"]', params.email);
|
||||
await this.page.fill('input[name="password"]', params.password);
|
||||
await this.page.click('button[type="submit"]');
|
||||
}
|
||||
|
||||
async signUp(params: {
|
||||
email: string,
|
||||
password: string,
|
||||
repeatPassword: string
|
||||
}) {
|
||||
await this.page.fill('input[name="email"]', params.email);
|
||||
await this.page.fill('input[name="password"]', params.password);
|
||||
await this.page.fill('input[name="repeatPassword"]', params.repeatPassword);
|
||||
await this.page.click('button[type="submit"]');
|
||||
}
|
||||
|
||||
async visitConfirmEmailLink(email: string) {
|
||||
await this.page.waitForTimeout(300);
|
||||
|
||||
return this.mailbox.visitMailbox(email);
|
||||
}
|
||||
|
||||
createRandomEmail() {
|
||||
const value = Math.random() * 1000;
|
||||
|
||||
return `${value.toFixed(0)}@makerkit.dev`;
|
||||
}
|
||||
}
|
||||
57
apps/e2e/tests/authentication/auth.spec.ts
Normal file
57
apps/e2e/tests/authentication/auth.spec.ts
Normal file
@@ -0,0 +1,57 @@
|
||||
import { test, expect } from '@playwright/test';
|
||||
import { AuthPageObject } from './auth.po';
|
||||
|
||||
test.describe('Auth flow', () => {
|
||||
test.describe.configure({ mode: 'serial' });
|
||||
|
||||
let email: string;
|
||||
|
||||
test('will sign-up and redirect to the home page', async ({ page }) => {
|
||||
const auth = new AuthPageObject(page);
|
||||
await auth.goToSignUp();
|
||||
|
||||
email = auth.createRandomEmail();
|
||||
|
||||
console.log(`Signing up with email ${email} ...`);
|
||||
|
||||
await auth.signUp({
|
||||
email,
|
||||
password: 'password',
|
||||
repeatPassword: 'password',
|
||||
});
|
||||
|
||||
await auth.visitConfirmEmailLink(email);
|
||||
|
||||
expect(page.url()).toContain('http://localhost:3000/home');
|
||||
});
|
||||
|
||||
test('will sign-in with the correct credentials', async ({ page }) => {
|
||||
const auth = new AuthPageObject(page);
|
||||
await auth.goToSignIn();
|
||||
|
||||
console.log(`Signing in with email ${email} ...`);
|
||||
|
||||
await auth.signIn({
|
||||
email,
|
||||
password: 'password',
|
||||
});
|
||||
|
||||
await page.waitForURL('http://localhost:3000/home');
|
||||
|
||||
expect(page.url()).toContain('http://localhost:3000/home');
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('Protected routes', () => {
|
||||
test('will redirect to the sign-in page if not authenticated', async ({ page }) => {
|
||||
await page.goto('/home/settings');
|
||||
|
||||
expect(page.url()).toContain('/auth/sign-in?next=/home/settings');
|
||||
});
|
||||
|
||||
test('will return a 404 for the admin page', async ({ page }) => {
|
||||
await page.goto('/admin')
|
||||
|
||||
expect(page.url()).toContain('/auth/sign-in');
|
||||
});
|
||||
})
|
||||
68
apps/e2e/tests/utils/mailbox.ts
Normal file
68
apps/e2e/tests/utils/mailbox.ts
Normal file
@@ -0,0 +1,68 @@
|
||||
import { Page } from '@playwright/test';
|
||||
import { parse } from 'node-html-parser';
|
||||
|
||||
export class Mailbox {
|
||||
constructor(
|
||||
private readonly page: Page
|
||||
) {
|
||||
}
|
||||
|
||||
async visitMailbox(email: string) {
|
||||
const mailbox = email.split('@')[0];
|
||||
|
||||
console.log(`Visiting mailbox ${mailbox} ...`)
|
||||
|
||||
if (!mailbox) {
|
||||
throw new Error('Invalid email');
|
||||
}
|
||||
|
||||
const json = await this.getInviteEmail(mailbox);
|
||||
|
||||
const html = (json.body as { html: string }).html;
|
||||
const el = parse(html);
|
||||
|
||||
const linkHref = el.querySelector('a')?.getAttribute('href');
|
||||
|
||||
if (!linkHref) {
|
||||
throw new Error('No link found in email');
|
||||
}
|
||||
|
||||
console.log(`Visiting ${linkHref} ...`);
|
||||
|
||||
return this.page.goto(linkHref);
|
||||
}
|
||||
|
||||
async getInviteEmail(
|
||||
mailbox: string,
|
||||
params = {
|
||||
deleteAfter: true
|
||||
}
|
||||
) {
|
||||
const url = `http://localhost:54324/api/v1/mailbox/${mailbox}`;
|
||||
|
||||
const response = await fetch(url);
|
||||
const json = (await response.json()) as Array<{ id: string }>;
|
||||
|
||||
if (!json || !json.length) {
|
||||
return;
|
||||
}
|
||||
|
||||
const messageId = json[0]?.id;
|
||||
const messageUrl = `${url}/${messageId}`;
|
||||
|
||||
const messageResponse = await fetch(messageUrl);
|
||||
|
||||
if (!messageResponse.ok) {
|
||||
throw new Error(`Failed to fetch email: ${messageResponse.statusText}`);
|
||||
}
|
||||
|
||||
// delete message
|
||||
if (params.deleteAfter) {
|
||||
await fetch(messageUrl, {
|
||||
method: 'DELETE'
|
||||
});
|
||||
}
|
||||
|
||||
return await messageResponse.json();
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -86,19 +86,20 @@ async function adminMiddleware(request: NextRequest, response: NextResponse) {
|
||||
|
||||
const supabase = createMiddlewareClient(request, response);
|
||||
const { data, error } = await supabase.auth.getUser();
|
||||
const host = request.nextUrl.host;
|
||||
|
||||
// If user is not logged in, redirect to sign in page.
|
||||
// This should never happen, but just in case.
|
||||
if (!data.user || error) {
|
||||
return NextResponse.redirect(`${host}/auth/sign-in`);
|
||||
return NextResponse.redirect(
|
||||
new URL(pathsConfig.auth.signIn, request.nextUrl.origin).href,
|
||||
);
|
||||
}
|
||||
|
||||
const role = data.user?.app_metadata.role;
|
||||
|
||||
// If user is not an admin, redirect to 404 page.
|
||||
if (!role || role !== 'super-admin') {
|
||||
return NextResponse.redirect(`${host}/404`);
|
||||
return NextResponse.redirect(new URL('/404', request.nextUrl.origin).href);
|
||||
}
|
||||
|
||||
// in all other cases, return the response
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
"lint": "turbo lint --continue -- --cache --cache-location 'node_modules/.cache/.eslintcache' && manypkg check",
|
||||
"lint:fix": "turbo lint --continue -- --fix --cache --cache-location 'node_modules/.cache/.eslintcache' && manypkg fix",
|
||||
"typecheck": "turbo typecheck",
|
||||
"test": "turbo test",
|
||||
"stripe:listen": "pnpm --filter '@kit/stripe' start"
|
||||
},
|
||||
"prettier": "@kit/prettier-config",
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
90
pnpm-lock.yaml
generated
90
pnpm-lock.yaml
generated
@@ -33,6 +33,21 @@ importers:
|
||||
specifier: ^1.22.22
|
||||
version: 1.22.22
|
||||
|
||||
apps/e2e:
|
||||
devDependencies:
|
||||
'@playwright/test':
|
||||
specifier: ^1.43.0
|
||||
version: 1.43.0
|
||||
'@types/node':
|
||||
specifier: ^20.12.7
|
||||
version: 20.12.7
|
||||
nanoid:
|
||||
specifier: ^5.0.7
|
||||
version: 5.0.7
|
||||
node-html-parser:
|
||||
specifier: ^6.1.13
|
||||
version: 6.1.13
|
||||
|
||||
apps/web:
|
||||
dependencies:
|
||||
'@epic-web/invariant':
|
||||
@@ -3385,6 +3400,14 @@ packages:
|
||||
requiresBuild: true
|
||||
optional: true
|
||||
|
||||
/@playwright/test@1.43.0:
|
||||
resolution: {integrity: sha512-Ebw0+MCqoYflop7wVKj711ccbNlrwTBCtjY5rlbiY9kHL2bCYxq+qltK6uPsVBGGAOb033H2VO0YobcQVxoW7Q==}
|
||||
engines: {node: '>=16'}
|
||||
hasBin: true
|
||||
dependencies:
|
||||
playwright: 1.43.0
|
||||
dev: true
|
||||
|
||||
/@pnpm/config.env-replace@1.1.0:
|
||||
resolution: {integrity: sha512-htyl8TWnKL7K/ESFa1oW2UB5lVDxuF5DpM7tBi6Hu2LNL3mWkIzNLG6N4zoCUP1lCKNxWy/3iu8mS8MvToGd6w==}
|
||||
engines: {node: '>=12.22.0'}
|
||||
@@ -7694,6 +7717,10 @@ packages:
|
||||
readable-stream: 3.6.2
|
||||
dev: false
|
||||
|
||||
/boolbase@1.0.0:
|
||||
resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==}
|
||||
dev: true
|
||||
|
||||
/brace-expansion@1.1.11:
|
||||
resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==}
|
||||
dependencies:
|
||||
@@ -8143,6 +8170,21 @@ packages:
|
||||
shebang-command: 2.0.0
|
||||
which: 2.0.2
|
||||
|
||||
/css-select@5.1.0:
|
||||
resolution: {integrity: sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==}
|
||||
dependencies:
|
||||
boolbase: 1.0.0
|
||||
css-what: 6.1.0
|
||||
domhandler: 5.0.3
|
||||
domutils: 3.1.0
|
||||
nth-check: 2.1.1
|
||||
dev: true
|
||||
|
||||
/css-what@6.1.0:
|
||||
resolution: {integrity: sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==}
|
||||
engines: {node: '>= 6'}
|
||||
dev: true
|
||||
|
||||
/cssesc@3.0.0:
|
||||
resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==}
|
||||
engines: {node: '>=4'}
|
||||
@@ -8453,18 +8495,15 @@ packages:
|
||||
domelementtype: 2.3.0
|
||||
domhandler: 5.0.3
|
||||
entities: 4.5.0
|
||||
dev: false
|
||||
|
||||
/domelementtype@2.3.0:
|
||||
resolution: {integrity: sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==}
|
||||
dev: false
|
||||
|
||||
/domhandler@5.0.3:
|
||||
resolution: {integrity: sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==}
|
||||
engines: {node: '>= 4'}
|
||||
dependencies:
|
||||
domelementtype: 2.3.0
|
||||
dev: false
|
||||
|
||||
/domutils@3.1.0:
|
||||
resolution: {integrity: sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==}
|
||||
@@ -8472,7 +8511,6 @@ packages:
|
||||
dom-serializer: 2.0.0
|
||||
domelementtype: 2.3.0
|
||||
domhandler: 5.0.3
|
||||
dev: false
|
||||
|
||||
/dot-case@2.1.1:
|
||||
resolution: {integrity: sha512-HnM6ZlFqcajLsyudHq7LeeLDr2rFAVYtDv/hV5qchQEidSck8j9OPUsXY9KwJv/lHMtYlX4DjRQqwFYa+0r8Ug==}
|
||||
@@ -8594,7 +8632,6 @@ packages:
|
||||
/entities@4.5.0:
|
||||
resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==}
|
||||
engines: {node: '>=0.12'}
|
||||
dev: false
|
||||
|
||||
/error-ex@1.3.2:
|
||||
resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==}
|
||||
@@ -9316,6 +9353,14 @@ packages:
|
||||
/fs.realpath@1.0.0:
|
||||
resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==}
|
||||
|
||||
/fsevents@2.3.2:
|
||||
resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==}
|
||||
engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
|
||||
os: [darwin]
|
||||
requiresBuild: true
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/fsevents@2.3.3:
|
||||
resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==}
|
||||
engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
|
||||
@@ -9614,6 +9659,11 @@ packages:
|
||||
dependencies:
|
||||
function-bind: 1.1.2
|
||||
|
||||
/he@1.2.0:
|
||||
resolution: {integrity: sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==}
|
||||
hasBin: true
|
||||
dev: true
|
||||
|
||||
/header-case@1.0.1:
|
||||
resolution: {integrity: sha512-i0q9mkOeSuhXw6bGgiQCCBgY/jlZuV/7dZXyZ9c6LcBrqwvT8eT719E9uxE5LiZftdl+z81Ugbg/VvXV4OJOeQ==}
|
||||
dependencies:
|
||||
@@ -11157,7 +11207,6 @@ packages:
|
||||
resolution: {integrity: sha512-oLxFY2gd2IqnjcYyOXD8XGCftpGtZP2AbHbOkthDkvRywH5ayNtPVy9YlOPcHckXzbLTCHpkb7FB+yuxKV13pQ==}
|
||||
engines: {node: ^18 || >=20}
|
||||
hasBin: true
|
||||
dev: false
|
||||
|
||||
/natural-compare@1.4.0:
|
||||
resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==}
|
||||
@@ -11351,6 +11400,13 @@ packages:
|
||||
formdata-polyfill: 4.0.10
|
||||
dev: true
|
||||
|
||||
/node-html-parser@6.1.13:
|
||||
resolution: {integrity: sha512-qIsTMOY4C/dAa5Q5vsobRpOOvPfC4pB61UVW2uSwZNUp0QU/jCekTal1vMmbO0DgdHeLUJpv/ARmDqErVxA3Sg==}
|
||||
dependencies:
|
||||
css-select: 5.1.0
|
||||
he: 1.2.0
|
||||
dev: true
|
||||
|
||||
/node-plop@0.26.3:
|
||||
resolution: {integrity: sha512-Cov028YhBZ5aB7MdMWJEmwyBig43aGL5WT4vdoB28Oitau1zZAcHUn8Sgfk9HM33TqhtLJ9PlM/O0Mv+QpV/4Q==}
|
||||
engines: {node: '>=8.9.4'}
|
||||
@@ -11409,6 +11465,12 @@ packages:
|
||||
path-key: 3.1.1
|
||||
dev: false
|
||||
|
||||
/nth-check@2.1.1:
|
||||
resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==}
|
||||
dependencies:
|
||||
boolbase: 1.0.0
|
||||
dev: true
|
||||
|
||||
/object-assign@4.1.1:
|
||||
resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
@@ -11776,6 +11838,22 @@ packages:
|
||||
resolution: {integrity: sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==}
|
||||
engines: {node: '>= 6'}
|
||||
|
||||
/playwright-core@1.43.0:
|
||||
resolution: {integrity: sha512-iWFjyBUH97+pUFiyTqSLd8cDMMOS0r2ZYz2qEsPjH8/bX++sbIJT35MSwKnp1r/OQBAqC5XO99xFbJ9XClhf4w==}
|
||||
engines: {node: '>=16'}
|
||||
hasBin: true
|
||||
dev: true
|
||||
|
||||
/playwright@1.43.0:
|
||||
resolution: {integrity: sha512-SiOKHbVjTSf6wHuGCbqrEyzlm6qvXcv7mENP+OZon1I07brfZLGdfWV0l/efAzVx7TF3Z45ov1gPEkku9q25YQ==}
|
||||
engines: {node: '>=16'}
|
||||
hasBin: true
|
||||
dependencies:
|
||||
playwright-core: 1.43.0
|
||||
optionalDependencies:
|
||||
fsevents: 2.3.2
|
||||
dev: true
|
||||
|
||||
/pnpm@8.15.6:
|
||||
resolution: {integrity: sha512-d7iem+d6Kwatj0A6Gcrl4il29hAj+YrTI9XDAZSVjrwC7gpq5dE+5FT2E05OjK8poF8LGg4dKxe8prah8RWfhg==}
|
||||
engines: {node: '>=16.14'}
|
||||
|
||||
@@ -45,6 +45,14 @@
|
||||
"node_modules/.cache/tsbuildinfo.json"
|
||||
]
|
||||
},
|
||||
"test": {
|
||||
"dependsOn": [
|
||||
"^topo"
|
||||
],
|
||||
"outputs": [
|
||||
"node_modules/.cache/tsbuildinfo.json"
|
||||
]
|
||||
},
|
||||
"clean": {
|
||||
"cache": false
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user