From 4af28412a0312f6fdfedb0c495d904daa762b50e Mon Sep 17 00:00:00 2001 From: Yisroel Baum Date: Tue, 2 Jun 2026 09:47:48 +0300 Subject: [PATCH] use ts cypress reset --- frontend/rabbi_gerzi/cypress.config.mjs | 38 ---- frontend/rabbi_gerzi/cypress.config.ts | 97 ++++++++++ .../rabbi_gerzi/cypress/support/commands.ts | 16 ++ frontend/rabbi_gerzi/cypress/support/e2e.ts | 4 +- frontend/rabbi_gerzi/cypress/tsconfig.json | 12 ++ frontend/rabbi_gerzi/package-lock.json | 174 ++++++++++++++++++ frontend/rabbi_gerzi/package.json | 2 + frontend/rabbi_gerzi/tsconfig.json | 7 +- 8 files changed, 310 insertions(+), 40 deletions(-) delete mode 100644 frontend/rabbi_gerzi/cypress.config.mjs create mode 100644 frontend/rabbi_gerzi/cypress.config.ts create mode 100644 frontend/rabbi_gerzi/cypress/support/commands.ts create mode 100644 frontend/rabbi_gerzi/cypress/tsconfig.json diff --git a/frontend/rabbi_gerzi/cypress.config.mjs b/frontend/rabbi_gerzi/cypress.config.mjs deleted file mode 100644 index 6717c51..0000000 --- a/frontend/rabbi_gerzi/cypress.config.mjs +++ /dev/null @@ -1,38 +0,0 @@ -import { execFileSync } from 'node:child_process' -import { dirname, resolve } from 'node:path' -import { fileURLToPath } from 'node:url' -import { defineConfig } from 'cypress' -import createBundler from '@bahmutov/cypress-esbuild-preprocessor' - -const configDirectory = dirname(fileURLToPath(import.meta.url)) -const backendDirectory = resolve(configDirectory, '../../backend') - -function resetDatabase() { - execFileSync( - 'php', - ['artisan', 'migrate:fresh', '--seed', '--force'], - { - cwd: backendDirectory, - stdio: 'inherit', - }, - ) - - return null -} - -export default defineConfig({ - e2e: { - baseUrl: 'http://localhost:5173', - specPattern: 'cypress/e2e/**/*.cy.ts', - supportFile: 'cypress/support/e2e.ts', - fixturesFolder: false, - video: false, - screenshotOnRunFailure: false, - setupNodeEvents(onEvent) { - onEvent('file:preprocessor', createBundler()) - onEvent('task', { - resetDatabase, - }) - }, - }, -}) diff --git a/frontend/rabbi_gerzi/cypress.config.ts b/frontend/rabbi_gerzi/cypress.config.ts new file mode 100644 index 0000000..82a9470 --- /dev/null +++ b/frontend/rabbi_gerzi/cypress.config.ts @@ -0,0 +1,97 @@ +import { execSync } from 'node:child_process' +import { dirname, resolve } from 'node:path' +import { fileURLToPath } from 'node:url' +import { defineConfig } from 'cypress' +import createBundler from '@bahmutov/cypress-esbuild-preprocessor' +import { Client } from 'pg' + +const configDirectory = dirname(fileURLToPath(import.meta.url)) +const backendDirectory = resolve(configDirectory, '../../backend') +const socketDirectory = resolve(configDirectory, '../../.postgres') +const appDatabase = 'postgres' +const templateDatabase = 'postgres_cypress_template' + +function controlClient(): Client { + return new Client({ + host: socketDirectory, + database: 'template1', + user: 'postgres', + }) +} + +async function buildTemplate(): Promise { + const setupClient = controlClient() + await setupClient.connect() + await setupClient.query( + `UPDATE pg_database SET datistemplate = false + WHERE datname = $1`, + [templateDatabase], + ) + await setupClient.query( + `SELECT pg_terminate_backend(pid) FROM pg_stat_activity + WHERE datname = $1 AND pid <> pg_backend_pid()`, + [templateDatabase], + ) + await setupClient.query(`DROP DATABASE IF EXISTS ${templateDatabase}`) + await setupClient.query(`CREATE DATABASE ${templateDatabase}`) + await setupClient.end() + + const seedEnvironment = { ...process.env, DB_DATABASE: templateDatabase } + execSync('php artisan migrate:fresh --force', { + cwd: backendDirectory, + stdio: 'pipe', + env: seedEnvironment, + }) + execSync('php artisan db:seed --force', { + cwd: backendDirectory, + stdio: 'pipe', + env: seedEnvironment, + }) + + const markClient = controlClient() + await markClient.connect() + await markClient.query( + `UPDATE pg_database SET datistemplate = true + WHERE datname = $1`, + [templateDatabase], + ) + await markClient.end() +} + +async function resetFromTemplate(): Promise { + const client = controlClient() + await client.connect() + await client.query( + `SELECT pg_terminate_backend(pid) FROM pg_stat_activity + WHERE datname IN ($1, $2) AND pid <> pg_backend_pid()`, + [appDatabase, templateDatabase], + ) + await client.query(`DROP DATABASE IF EXISTS ${appDatabase}`) + await client.query( + `CREATE DATABASE ${appDatabase} + TEMPLATE ${templateDatabase}`, + ) + await client.end() + + return null +} + +export default defineConfig({ + e2e: { + baseUrl: 'http://localhost:5173', + specPattern: 'cypress/e2e/**/*.cy.ts', + supportFile: 'cypress/support/e2e.ts', + fixturesFolder: false, + video: false, + screenshotOnRunFailure: false, + setupNodeEvents(onEvent) { + onEvent('before:run', async function () { + await buildTemplate() + }) + onEvent('file:preprocessor', createBundler()) + onEvent('task', { + 'db:reset': resetFromTemplate, + }) + }, + }, +}) diff --git a/frontend/rabbi_gerzi/cypress/support/commands.ts b/frontend/rabbi_gerzi/cypress/support/commands.ts new file mode 100644 index 0000000..65696c1 --- /dev/null +++ b/frontend/rabbi_gerzi/cypress/support/commands.ts @@ -0,0 +1,16 @@ +/// +/* eslint-disable @typescript-eslint/no-namespace */ + +declare global { + namespace Cypress { + interface Chainable { + resetDb(): Chainable + } + } +} + +Cypress.Commands.add('resetDb', function () { + return cy.task('db:reset') +}) + +export {} diff --git a/frontend/rabbi_gerzi/cypress/support/e2e.ts b/frontend/rabbi_gerzi/cypress/support/e2e.ts index 986240d..c8f94e6 100644 --- a/frontend/rabbi_gerzi/cypress/support/e2e.ts +++ b/frontend/rabbi_gerzi/cypress/support/e2e.ts @@ -1,5 +1,7 @@ +import './commands' + beforeEach(() => { - cy.task('resetDatabase') + cy.resetDb() cy.clearCookies() cy.clearLocalStorage() }) diff --git a/frontend/rabbi_gerzi/cypress/tsconfig.json b/frontend/rabbi_gerzi/cypress/tsconfig.json new file mode 100644 index 0000000..ddfb30e --- /dev/null +++ b/frontend/rabbi_gerzi/cypress/tsconfig.json @@ -0,0 +1,12 @@ +{ + "extends": "../tsconfig.app.json", + "include": ["./**/*.ts"], + "compilerOptions": { + "types": ["cypress", "node"], + "isolatedModules": false, + "noUncheckedIndexedAccess": false, + "noEmit": false, + "allowImportingTsExtensions": false, + "ignoreDeprecations": "6.0" + } +} diff --git a/frontend/rabbi_gerzi/package-lock.json b/frontend/rabbi_gerzi/package-lock.json index b1578ed..cd5beb4 100644 --- a/frontend/rabbi_gerzi/package-lock.json +++ b/frontend/rabbi_gerzi/package-lock.json @@ -16,6 +16,7 @@ "@bahmutov/cypress-esbuild-preprocessor": "^2.2.8", "@tsconfig/node24": "^24.0.4", "@types/node": "^24.12.2", + "@types/pg": "^8.20.0", "@vitejs/plugin-vue": "^6.0.6", "@vitejs/plugin-vue-jsx": "^5.1.5", "@vue/eslint-config-typescript": "^14.7.0", @@ -30,6 +31,7 @@ "npm-run-all2": "^8.0.4", "oxfmt": "^0.45.0", "oxlint": "~1.60.0", + "pg": "^8.21.0", "typescript": "~6.0.0", "vite": "^8.0.8", "vite-plugin-vue-devtools": "^8.1.1", @@ -2344,6 +2346,18 @@ "undici-types": "~7.16.0" } }, + "node_modules/@types/pg": { + "version": "8.20.0", + "resolved": "https://registry.npmjs.org/@types/pg/-/pg-8.20.0.tgz", + "integrity": "sha512-bEPFOaMAHTEP1EzpvHTbmwR8UsFyHSKsRisLIHVMXnpNefSbGA1bD6CVy+qKjGSqmZqNqBDV2azOBo8TgkcVow==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*", + "pg-protocol": "*", + "pg-types": "^2.2.0" + } + }, "node_modules/@types/sinonjs__fake-timers": { "version": "8.1.1", "resolved": "https://registry.npmjs.org/@types/sinonjs__fake-timers/-/sinonjs__fake-timers-8.1.1.tgz", @@ -6495,6 +6509,103 @@ "dev": true, "license": "MIT" }, + "node_modules/pg": { + "version": "8.21.0", + "resolved": "https://registry.npmjs.org/pg/-/pg-8.21.0.tgz", + "integrity": "sha512-AUP1EYJuHraQGsVoCQVIcM7TEJVGtDzxWtGFZd8rds9d+CCXlU5Js1rYgfLNvxy9iJrpHjGrRjoi/3BT9fRyiA==", + "dev": true, + "license": "MIT", + "dependencies": { + "pg-connection-string": "^2.13.0", + "pg-pool": "^3.14.0", + "pg-protocol": "^1.14.0", + "pg-types": "2.2.0", + "pgpass": "1.0.5" + }, + "engines": { + "node": ">= 16.0.0" + }, + "optionalDependencies": { + "pg-cloudflare": "^1.4.0" + }, + "peerDependencies": { + "pg-native": ">=3.0.1" + }, + "peerDependenciesMeta": { + "pg-native": { + "optional": true + } + } + }, + "node_modules/pg-cloudflare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/pg-cloudflare/-/pg-cloudflare-1.4.0.tgz", + "integrity": "sha512-Vo7z/6rrQYxpNRylp4Tlob2elzbh+N/MOQbxFVWCxS7oEx6jF53GTJFxK2WWpKuBRkmiin4Mt+xofFDjx09R0A==", + "dev": true, + "license": "MIT", + "optional": true + }, + "node_modules/pg-connection-string": { + "version": "2.13.0", + "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.13.0.tgz", + "integrity": "sha512-EMnU9E2fSULdsbErBbMaXJvFeD9B4+nPcM3f+4lsiCR0BHLPrLVjv3DbyM2hgQQviKJaTWIRRTjKjWlHg3p2ig==", + "dev": true, + "license": "MIT" + }, + "node_modules/pg-int8": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/pg-int8/-/pg-int8-1.0.1.tgz", + "integrity": "sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/pg-pool": { + "version": "3.14.0", + "resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-3.14.0.tgz", + "integrity": "sha512-gKtPkFdQPU3DksooVLi9LsjZxrsBUZIpa+7aVx+LV5pNh0KzP4Zleud2po+ConrxbuXGBJ6Hfer6hdgpIBpBaw==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "pg": ">=8.0" + } + }, + "node_modules/pg-protocol": { + "version": "1.14.0", + "resolved": "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.14.0.tgz", + "integrity": "sha512-n5taZ1kO3s9ngDTVxsEznOqCyToTgz0FLuPq0B33COy5pPpuWJpY3/2oRBVETuOgzdqRXfWpM9HIhp2LBBT1BA==", + "dev": true, + "license": "MIT" + }, + "node_modules/pg-types": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/pg-types/-/pg-types-2.2.0.tgz", + "integrity": "sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==", + "dev": true, + "license": "MIT", + "dependencies": { + "pg-int8": "1.0.1", + "postgres-array": "~2.0.0", + "postgres-bytea": "~1.0.0", + "postgres-date": "~1.0.4", + "postgres-interval": "^1.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/pgpass": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/pgpass/-/pgpass-1.0.5.tgz", + "integrity": "sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==", + "dev": true, + "license": "MIT", + "dependencies": { + "split2": "^4.1.0" + } + }, "node_modules/picocolors": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", @@ -6611,6 +6722,49 @@ "node": ">=4" } }, + "node_modules/postgres-array": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-2.0.0.tgz", + "integrity": "sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/postgres-bytea": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-1.0.1.tgz", + "integrity": "sha512-5+5HqXnsZPE65IJZSMkZtURARZelel2oXUEO8rH83VS/hxH5vv1uHquPg5wZs8yMAfdv971IU+kcPUczi7NVBQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postgres-date": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/postgres-date/-/postgres-date-1.0.7.tgz", + "integrity": "sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postgres-interval": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/postgres-interval/-/postgres-interval-1.2.0.tgz", + "integrity": "sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "xtend": "^4.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/prelude-ls": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", @@ -7101,6 +7255,16 @@ "node": ">=0.10.0" } }, + "node_modules/split2": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz", + "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">= 10.x" + } + }, "node_modules/sshpk": { "version": "1.18.0", "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.18.0.tgz", @@ -8226,6 +8390,16 @@ "node": ">=12" } }, + "node_modules/xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.4" + } + }, "node_modules/yallist": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", diff --git a/frontend/rabbi_gerzi/package.json b/frontend/rabbi_gerzi/package.json index 18bec3a..0506b7b 100644 --- a/frontend/rabbi_gerzi/package.json +++ b/frontend/rabbi_gerzi/package.json @@ -25,6 +25,7 @@ "@bahmutov/cypress-esbuild-preprocessor": "^2.2.8", "@tsconfig/node24": "^24.0.4", "@types/node": "^24.12.2", + "@types/pg": "^8.20.0", "@vitejs/plugin-vue": "^6.0.6", "@vitejs/plugin-vue-jsx": "^5.1.5", "@vue/eslint-config-typescript": "^14.7.0", @@ -39,6 +40,7 @@ "npm-run-all2": "^8.0.4", "oxfmt": "^0.45.0", "oxlint": "~1.60.0", + "pg": "^8.21.0", "typescript": "~6.0.0", "vite": "^8.0.8", "vite-plugin-vue-devtools": "^8.1.1", diff --git a/frontend/rabbi_gerzi/tsconfig.json b/frontend/rabbi_gerzi/tsconfig.json index 66b5e57..8d99c04 100644 --- a/frontend/rabbi_gerzi/tsconfig.json +++ b/frontend/rabbi_gerzi/tsconfig.json @@ -7,5 +7,10 @@ { "path": "./tsconfig.app.json" } - ] + ], + "compilerOptions": { + "module": "ESNext", + "moduleResolution": "bundler", + "ignoreDeprecations": "6.0" + } }