@testspectra/cli 1.1.7 → 1.1.8-rc.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +47 -0
- package/demo-app/assets/index-BhlW-eXG.css +1 -0
- package/demo-app/assets/index-DOtRypCa.js +154 -0
- package/demo-app/index.html +2 -2
- package/dist/.tsbuildinfo +1 -1
- package/dist/commands/__tests__/run-e2e.test.js +254 -13
- package/dist/commands/__tests__/run.test.js +92 -16
- package/dist/commands/add.js +2 -1
- package/dist/commands/demo.js +17 -7
- package/dist/commands/init.d.ts +1 -1
- package/dist/commands/init.js +8 -2
- package/dist/commands/lint.d.ts +5 -0
- package/dist/commands/lint.js +55 -0
- package/dist/commands/refactor.d.ts +2 -1
- package/dist/commands/refactor.js +129 -35
- package/dist/commands/run.d.ts +2 -3
- package/dist/commands/run.js +93 -28
- package/dist/commands/skills.d.ts +9 -0
- package/dist/commands/skills.js +28 -0
- package/dist/commands/sync-types.js +1 -0
- package/dist/commands/test.d.ts +17 -0
- package/dist/commands/test.js +104 -0
- package/dist/commands/watch.js +9 -3
- package/dist/config/loader.js +1 -1
- package/dist/config/schema.d.ts +5 -114
- package/dist/config/schema.js +1 -17
- package/dist/generator/__tests__/tsconfig-isolation.test.js +6 -2
- package/dist/generator/__tests__/type-generator.test.js +39 -1
- package/dist/generator/tsconfig-generator.js +44 -16
- package/dist/generator/type-generator.d.ts +29 -3
- package/dist/generator/type-generator.js +115 -22
- package/dist/index.d.ts +1 -1
- package/dist/index.js +65 -29
- package/dist/linter/__tests__/anonymous-export.test.js +184 -0
- package/dist/linter/__tests__/component-test-imports.test.d.ts +1 -0
- package/dist/linter/__tests__/component-test-imports.test.js +115 -0
- package/dist/linter/__tests__/shared-lib-boundary.test.d.ts +1 -0
- package/dist/linter/__tests__/shared-lib-boundary.test.js +270 -0
- package/dist/linter/__tests__/spec-schema.test.d.ts +1 -0
- package/dist/linter/__tests__/spec-schema.test.js +369 -0
- package/dist/linter/__tests__/step-parity.test.d.ts +1 -0
- package/dist/linter/__tests__/step-parity.test.js +372 -0
- package/dist/linter/discovery.d.ts +30 -0
- package/dist/linter/discovery.js +249 -0
- package/dist/linter/extractor.d.ts +67 -0
- package/dist/linter/extractor.js +245 -0
- package/dist/linter/index.d.ts +7 -0
- package/dist/linter/index.js +7 -0
- package/dist/linter/parser.d.ts +24 -0
- package/dist/linter/parser.js +219 -0
- package/dist/linter/schemas/spec.schema.d.ts +83 -0
- package/dist/linter/schemas/spec.schema.js +150 -0
- package/dist/linter/schemas/suite.schema.d.ts +59 -0
- package/dist/linter/schemas/suite.schema.js +83 -0
- package/dist/linter/spec-linter.d.ts +23 -0
- package/dist/linter/spec-linter.js +630 -0
- package/dist/linter/types.d.ts +28 -0
- package/dist/linter/types.js +1 -0
- package/dist/refactor/__tests__/refactor-engine.test.js +698 -0
- package/dist/refactor/refactor-engine.d.ts +25 -0
- package/dist/refactor/refactor-engine.js +374 -42
- package/dist/reporter/semantic-formatter.js +22 -2
- package/dist/reporter/types.d.ts +1 -1
- package/dist/runner/bridge.d.ts +1 -1
- package/dist/runner/bridge.js +85 -24
- package/dist/runner/reporter.d.ts +2 -0
- package/dist/runner/reporter.js +11 -3
- package/dist/utils/__tests__/api-server.test.d.ts +1 -0
- package/dist/utils/__tests__/api-server.test.js +62 -0
- package/dist/utils/__tests__/demo-server.test.d.ts +1 -0
- package/dist/utils/__tests__/demo-server.test.js +35 -0
- package/dist/utils/api-server.d.ts +19 -0
- package/dist/utils/api-server.js +179 -0
- package/dist/utils/demo-server.d.ts +5 -0
- package/dist/utils/demo-server.js +8 -1
- package/package.json +13 -4
- package/templates/default/CLAUDE.md +5 -0
- package/templates/default/package.json +3 -3
- package/templates/default/page-objects/AuthPage/mobile.ts +5 -0
- package/templates/default/page-objects/AuthPage/web.ts +10 -0
- package/templates/default/page-objects/MatchersPage/mobile.ts +26 -2
- package/templates/default/page-objects/MatchersPage/web.ts +8 -2
- package/templates/default/page-objects/NavigationPage/mobile.ts +1 -1
- package/templates/default/page-objects/NavigationPage/web.ts +1 -1
- package/templates/default/page-objects/PlaygroundPage/mobile.ts +12 -6
- package/templates/default/page-objects/PlaygroundPage/web.ts +2 -2
- package/templates/default/specs/ApiInterception/TC-0008-fetch-mocking/mobile.test.ts +45 -3
- package/templates/default/specs/ApiInterception/TC-0008-fetch-mocking/spec.md +7 -0
- package/templates/default/specs/ApiInterception/TC-0008-fetch-mocking/web.test.ts +8 -4
- package/templates/default/specs/ApiInterception/TC-0009-post-mocking/android.test.ts +3 -0
- package/templates/default/specs/ApiInterception/TC-0009-post-mocking/common.test.ts +3 -0
- package/templates/default/specs/ApiInterception/TC-0009-post-mocking/mobile.test.ts +13 -2
- package/templates/default/specs/ApiInterception/TC-0009-post-mocking/spec.md +7 -0
- package/templates/default/specs/ApiInterception/TC-0009-post-mocking/web.test.ts +6 -4
- package/templates/default/specs/ApiInterception/TC-0012-direct-and-late-response/common.test.ts +30 -0
- package/templates/default/specs/ApiInterception/TC-0012-direct-and-late-response/spec.md +22 -0
- package/templates/default/specs/ApiInterception/TC-0013-real-network-call-recorded/common.test.ts +27 -0
- package/templates/default/specs/ApiInterception/TC-0013-real-network-call-recorded/spec.md +20 -0
- package/templates/default/specs/ApiInterception/TC-0015-mock-server-sent-events/spec.md +24 -0
- package/templates/default/specs/ApiInterception/TC-0015-mock-server-sent-events/web.test.ts +26 -0
- package/templates/default/specs/ApiInterception/TC-0016-bypass-websocket-with-app-level-mock/spec.md +37 -0
- package/templates/default/specs/ApiInterception/TC-0016-bypass-websocket-with-app-level-mock/web.test.ts +21 -0
- package/templates/default/specs/ApiInterception/TC-0017-bypass-captcha-with-test-mode-flag/spec.md +29 -0
- package/templates/default/specs/ApiInterception/TC-0017-bypass-captcha-with-test-mode-flag/web.test.ts +16 -0
- package/templates/default/specs/ApiInterception/suite.md +1 -0
- package/templates/default/specs/ApiSeeding/TC-0014-seed-and-cleanup-via-hooks/common.test.ts +30 -0
- package/templates/default/specs/ApiSeeding/TC-0014-seed-and-cleanup-via-hooks/spec.md +23 -0
- package/templates/default/specs/ApiSeeding/hooks/after/common.hook.ts +16 -0
- package/templates/default/specs/ApiSeeding/hooks/before/common.hook.ts +28 -0
- package/templates/default/specs/ApiSeeding/suite.md +9 -0
- package/templates/default/specs/Authentication/TC-0021-seed-authenticated-session/mobile.test.ts +7 -0
- package/templates/default/specs/Authentication/TC-0021-seed-authenticated-session/spec.md +19 -0
- package/templates/default/specs/Authentication/TC-0021-seed-authenticated-session/web.test.ts +9 -0
- package/templates/default/specs/Authentication/suite.md +9 -0
- package/templates/default/specs/BrowserContext/TC-0007-title-and-navigation/mobile.test.ts +1 -1
- package/templates/default/specs/BrowserContext/TC-0007-title-and-navigation/spec.md +5 -0
- package/templates/default/specs/BrowserContext/TC-0007-title-and-navigation/web.test.ts +1 -1
- package/templates/default/specs/BrowserContext/TC-0022-history-navigation/mobile.test.ts +17 -0
- package/templates/default/specs/BrowserContext/TC-0022-history-navigation/spec.md +28 -0
- package/templates/default/specs/BrowserContext/TC-0022-history-navigation/web.test.ts +26 -0
- package/templates/default/specs/ContentMatchers/TC-0005-text-and-values/common.test.ts +26 -0
- package/templates/default/specs/ContentMatchers/TC-0005-text-and-values/spec.md +7 -0
- package/templates/default/specs/ContentMatchers/TC-0006-collections-and-empty/mobile.test.ts +1 -1
- package/templates/default/specs/ContentMatchers/TC-0006-collections-and-empty/spec.md +5 -0
- package/templates/default/specs/ContentMatchers/TC-0006-collections-and-empty/web.test.ts +1 -1
- package/templates/default/specs/ContentMatchers/TC-0020-scoped-element-access/common.test.ts +14 -0
- package/templates/default/specs/ContentMatchers/TC-0020-scoped-element-access/spec.md +21 -0
- package/templates/default/specs/DeepLink/TC-0018-navigate-via-deep-link/mobile.test.ts +28 -0
- package/templates/default/specs/DeepLink/TC-0018-navigate-via-deep-link/spec.md +29 -0
- package/templates/default/specs/DeepLink/suite.md +9 -0
- package/templates/default/specs/ElementMatchers/TC-0003-visibility-and-dom/mobile.test.ts +1 -1
- package/templates/default/specs/ElementMatchers/TC-0003-visibility-and-dom/spec.md +5 -0
- package/templates/default/specs/ElementMatchers/TC-0003-visibility-and-dom/web.test.ts +1 -1
- package/templates/default/specs/ElementMatchers/TC-0004-states-and-attributes/mobile.test.ts +1 -1
- package/templates/default/specs/ElementMatchers/TC-0004-states-and-attributes/spec.md +7 -0
- package/templates/default/specs/ElementMatchers/TC-0004-states-and-attributes/web.test.ts +1 -1
- package/templates/default/specs/ElementMatchers/suite.md +2 -1
- package/templates/default/specs/EnvironmentConfig/TC-0019-read-custom-environment-variable/common.test.ts +5 -0
- package/templates/default/specs/EnvironmentConfig/TC-0019-read-custom-environment-variable/spec.md +16 -0
- package/templates/default/specs/EnvironmentConfig/suite.md +9 -0
- package/templates/default/specs/PermissionRationale/TC-0010-camera-permission-allow/mobile.test.ts +26 -0
- package/templates/default/specs/PermissionRationale/TC-0010-camera-permission-allow/spec.md +22 -0
- package/templates/default/specs/PermissionRationale/TC-0011-camera-permission-deny/mobile.test.ts +13 -0
- package/templates/default/specs/PermissionRationale/TC-0011-camera-permission-deny/spec.md +20 -0
- package/templates/default/specs/PermissionRationale/suite.md +9 -0
- package/templates/default/specs/Playground/TC-0001-form-controls/mobile.test.ts +1 -1
- package/templates/default/specs/Playground/TC-0001-form-controls/spec.md +6 -0
- package/templates/default/specs/Playground/TC-0001-form-controls/web.test.ts +1 -1
- package/templates/default/specs/Playground/TC-0002-toggle-elements/mobile.test.ts +1 -1
- package/templates/default/specs/Playground/TC-0002-toggle-elements/spec.md +6 -0
- package/templates/default/specs/Playground/TC-0002-toggle-elements/web.test.ts +1 -1
- package/templates/default/spectra.config.ts +1 -17
- package/templates/default/support/actions/fillCredentials/mobile.action.ts +3 -3
- package/templates/default/support/actions/fillCredentials/web.action.ts +1 -1
- package/templates/default/support/actions/seedSession/mobile.action.ts +9 -0
- package/templates/default/support/actions/seedSession/web.action.ts +13 -0
- package/templates/default/support/steps/togglePlaygroundStates/mobile.step.ts +1 -1
- package/templates/default/support/steps/togglePlaygroundStates/web.step.ts +1 -1
- package/templates/default/support/steps/verifyPlaygroundState/mobile.step.ts +1 -1
- package/templates/default/support/steps/verifyPlaygroundState/web.step.ts +1 -1
- package/templates/nx/.nx/workspace-data/70094CFD-E89B-57A1-9619-2FC5F4963C54.db +0 -0
- package/templates/nx/.nx/workspace-data/70094CFD-E89B-57A1-9619-2FC5F4963C54.db-shm +0 -0
- package/templates/nx/.nx/workspace-data/70094CFD-E89B-57A1-9619-2FC5F4963C54.db-wal +0 -0
- package/templates/nx/.nx/workspace-data/d/daemon.log +5803 -168
- package/templates/nx/.nx/workspace-data/d/server-process.json +3 -0
- package/templates/nx/.nx/workspace-data/file-map.json +464 -0
- package/templates/nx/.nx/workspace-data/lockfile.hash +1 -0
- package/templates/nx/.nx/workspace-data/nx_files.nxt +0 -0
- package/templates/nx/.nx/workspace-data/parsed-lock-file.json +13485 -0
- package/templates/nx/.nx/workspace-data/project-graph.json +14388 -0
- package/templates/nx/package.json +3 -3
- package/templates/nx/packages/matchers/e2e/project.json +2 -2
- package/templates/nx/packages/matchers/e2e/specs/ApiInterception/TC-0008-fetch-mocking/mobile.test.ts +25 -1
- package/templates/nx/packages/matchers/e2e/specs/ApiInterception/TC-0008-fetch-mocking/web.test.ts +2 -2
- package/templates/nx/packages/matchers/e2e/specs/ApiInterception/TC-0009-post-mocking/mobile.test.ts +22 -1
- package/templates/nx/packages/matchers/e2e/specs/ApiInterception/TC-0009-post-mocking/web.test.ts +2 -2
- package/templates/nx/packages/matchers/e2e/specs/BrowserContext/TC-0007-title-and-navigation/mobile.test.ts +1 -1
- package/templates/nx/packages/matchers/e2e/specs/BrowserContext/TC-0007-title-and-navigation/web.test.ts +1 -1
- package/templates/nx/packages/matchers/e2e/specs/ContentMatchers/TC-0005-text-and-values/mobile.test.ts +1 -1
- package/templates/nx/packages/matchers/e2e/specs/ContentMatchers/TC-0005-text-and-values/web.test.ts +1 -1
- package/templates/nx/packages/matchers/e2e/specs/ContentMatchers/TC-0006-collections-and-empty/mobile.test.ts +1 -1
- package/templates/nx/packages/matchers/e2e/specs/ContentMatchers/TC-0006-collections-and-empty/web.test.ts +1 -1
- package/templates/nx/packages/matchers/e2e/specs/ElementMatchers/TC-0003-visibility-and-dom/mobile.test.ts +1 -1
- package/templates/nx/packages/matchers/e2e/specs/ElementMatchers/TC-0003-visibility-and-dom/web.test.ts +1 -1
- package/templates/nx/packages/matchers/e2e/specs/ElementMatchers/TC-0004-states-and-attributes/mobile.test.ts +1 -1
- package/templates/nx/packages/matchers/e2e/specs/ElementMatchers/TC-0004-states-and-attributes/web.test.ts +1 -1
- package/templates/nx/packages/matchers/e2e/specs/EnvironmentConfig/TC-0019-read-custom-environment-variable/common.test.ts +5 -0
- package/templates/nx/packages/matchers/e2e/specs/EnvironmentConfig/TC-0019-read-custom-environment-variable/spec.md +16 -0
- package/templates/nx/packages/matchers/e2e/specs/EnvironmentConfig/suite.md +9 -0
- package/templates/nx/packages/playground/e2e/project.json +2 -2
- package/templates/nx/packages/playground/e2e/specs/Playground/TC-0001-form-controls/mobile.test.ts +1 -1
- package/templates/nx/packages/playground/e2e/specs/Playground/TC-0001-form-controls/web.test.ts +1 -1
- package/templates/nx/packages/playground/e2e/specs/Playground/TC-0002-toggle-elements/mobile.test.ts +1 -1
- package/templates/nx/packages/playground/e2e/specs/Playground/TC-0002-toggle-elements/web.test.ts +1 -1
- package/templates/nx/shared/testing/page-objects/MatchersPage/mobile.ts +1 -1
- package/templates/nx/shared/testing/page-objects/MatchersPage/web.ts +83 -29
- package/templates/nx/shared/testing/page-objects/NavigationPage/mobile.ts +1 -1
- package/templates/nx/shared/testing/page-objects/NavigationPage/web.ts +1 -1
- package/templates/nx/shared/testing/page-objects/PlaygroundPage/mobile.ts +1 -1
- package/templates/nx/shared/testing/page-objects/PlaygroundPage/web.ts +2 -2
- package/templates/nx/shared/testing/project.json +1 -2
- package/templates/nx/shared/testing/support/actions/fillCredentials/mobile.action.ts +1 -1
- package/templates/nx/shared/testing/support/actions/fillCredentials/web.action.ts +1 -1
- package/templates/nx/shared/testing/support/steps/togglePlaygroundStates/mobile.step.ts +1 -1
- package/templates/nx/shared/testing/support/steps/togglePlaygroundStates/web.step.ts +1 -1
- package/templates/nx/shared/testing/support/steps/verifyPlaygroundState/mobile.step.ts +1 -1
- package/templates/nx/shared/testing/support/steps/verifyPlaygroundState/web.step.ts +1 -1
- package/templates/nx/spectra.config.ts +1 -17
- package/templates/react-component/.cursorrules +17 -0
- package/templates/react-component/.vscode/extensions.json +5 -0
- package/templates/react-component/CLAUDE.md +14 -0
- package/templates/react-component/README.md +69 -0
- package/templates/react-component/fixtures/component-mock.json +12 -0
- package/templates/react-component/global-hooks/after/web.hook.ts +3 -0
- package/templates/react-component/global-hooks/before/web.hook.ts +3 -0
- package/templates/react-component/package.json +27 -0
- package/templates/react-component/page-objects/BadgeComponent/web.ts +23 -0
- package/templates/react-component/page-objects/ButtonComponent/web.ts +23 -0
- package/templates/react-component/page-objects/InputComponent/web.ts +13 -0
- package/templates/react-component/specs/BadgeComponent/TC-0002-badge-severities-and-dot/spec.md +18 -0
- package/templates/react-component/specs/BadgeComponent/TC-0002-badge-severities-and-dot/web.test.tsx +11 -0
- package/templates/react-component/specs/BadgeComponent/TC-0006-badge-success-with-dot/spec.md +18 -0
- package/templates/react-component/specs/BadgeComponent/TC-0006-badge-success-with-dot/web.test.tsx +10 -0
- package/templates/react-component/specs/BadgeComponent/TC-0007-badge-by-severity-lookup/spec.md +18 -0
- package/templates/react-component/specs/BadgeComponent/TC-0007-badge-by-severity-lookup/web.test.tsx +16 -0
- package/templates/react-component/specs/BadgeComponent/suite.md +12 -0
- package/templates/react-component/specs/ButtonComponent/TC-0001-button-rendering-and-click/spec.md +19 -0
- package/templates/react-component/specs/ButtonComponent/TC-0001-button-rendering-and-click/web.test.tsx +28 -0
- package/templates/react-component/specs/ButtonComponent/TC-0004-disabled-button-not-clickable/spec.md +19 -0
- package/templates/react-component/specs/ButtonComponent/TC-0004-disabled-button-not-clickable/web.test.tsx +22 -0
- package/templates/react-component/specs/ButtonComponent/TC-0005-button-renders-icon/spec.md +18 -0
- package/templates/react-component/specs/ButtonComponent/TC-0005-button-renders-icon/web.test.tsx +8 -0
- package/templates/react-component/specs/ButtonComponent/suite.md +12 -0
- package/templates/react-component/specs/InputComponent/TC-0003-input-typing-and-clear/spec.md +20 -0
- package/templates/react-component/specs/InputComponent/TC-0003-input-typing-and-clear/web.test.tsx +28 -0
- package/templates/react-component/specs/InputComponent/TC-0008-disabled-input-not-editable/spec.md +18 -0
- package/templates/react-component/specs/InputComponent/TC-0008-disabled-input-not-editable/web.test.tsx +9 -0
- package/templates/react-component/specs/InputComponent/suite.md +12 -0
- package/templates/react-component/spectra.config.ts +27 -0
- package/templates/react-component/src/components/Badge/Badge.tsx +60 -0
- package/templates/react-component/src/components/Button/Button.tsx +57 -0
- package/templates/react-component/src/components/Input/Input.tsx +41 -0
- package/templates/react-component/src/test-utils.tsx +23 -0
- package/templates/react-component/support/actions/fillInputField/web.action.ts +9 -0
- package/templates/react-component/support/steps/verifyButtonState/web.step.ts +12 -0
- package/templates/react-component/tsconfig.json +8 -0
- package/bin/.testspectra-runner.hash +0 -1
- package/bin/testspectra-runner +0 -0
- package/demo-app/assets/index-DPfv5_EF.js +0 -116
- package/demo-app/assets/index-gIwu2EMV.css +0 -1
- package/dist/commands/__tests__/cloud-run.test.js +0 -93
- package/dist/commands/cloud-run.d.ts +0 -13
- package/dist/commands/cloud-run.js +0 -120
- package/templates/default/specs/ContentMatchers/TC-0005-text-and-values/mobile.test.ts +0 -17
- package/templates/default/specs/ContentMatchers/TC-0005-text-and-values/web.test.ts +0 -17
- /package/dist/{commands/__tests__/cloud-run.test.d.ts → linter/__tests__/anonymous-export.test.d.ts} +0 -0
|
@@ -1,93 +0,0 @@
|
|
|
1
|
-
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
|
2
|
-
import { cloudRunCommand, parseTimeoutMs } from '../cloud-run.js';
|
|
3
|
-
const ORIGINAL_ENV = { ...process.env };
|
|
4
|
-
function mockFetchSequence(responses) {
|
|
5
|
-
let call = 0;
|
|
6
|
-
return vi.fn(async (_url, _init) => {
|
|
7
|
-
const res = responses[Math.min(call, responses.length - 1)];
|
|
8
|
-
call += 1;
|
|
9
|
-
return {
|
|
10
|
-
ok: res.ok,
|
|
11
|
-
status: res.status ?? (res.ok ? 200 : 500),
|
|
12
|
-
statusText: 'error',
|
|
13
|
-
json: async () => res.json,
|
|
14
|
-
};
|
|
15
|
-
});
|
|
16
|
-
}
|
|
17
|
-
describe('cloudRunCommand (docs/v2/cloud/git-spec-standards-and-workflow.md)', () => {
|
|
18
|
-
beforeEach(() => {
|
|
19
|
-
process.env = { ...ORIGINAL_ENV, SPECTRA_URL: 'https://cloud.test', SPECTRA_TOKEN: 'gitea-pat-123' };
|
|
20
|
-
process.exitCode = undefined;
|
|
21
|
-
vi.useFakeTimers();
|
|
22
|
-
});
|
|
23
|
-
afterEach(() => {
|
|
24
|
-
process.env = { ...ORIGINAL_ENV };
|
|
25
|
-
vi.restoreAllMocks();
|
|
26
|
-
vi.useRealTimers();
|
|
27
|
-
});
|
|
28
|
-
it('fails fast without SPECTRA_URL/SPECTRA_TOKEN', async () => {
|
|
29
|
-
delete process.env.SPECTRA_URL;
|
|
30
|
-
delete process.env.SPECTRA_TOKEN;
|
|
31
|
-
const fetchSpy = vi.fn();
|
|
32
|
-
vi.stubGlobal('fetch', fetchSpy);
|
|
33
|
-
await cloudRunCommand({ project: 'org/repo', branch: 'main' });
|
|
34
|
-
expect(process.exitCode).toBe(1);
|
|
35
|
-
expect(fetchSpy).not.toHaveBeenCalled();
|
|
36
|
-
});
|
|
37
|
-
it('triggers and returns immediately with --no-wait', async () => {
|
|
38
|
-
const fetchSpy = mockFetchSequence([{ ok: true, json: { job_id: 'job-1', status: 'queued' } }]);
|
|
39
|
-
vi.stubGlobal('fetch', fetchSpy);
|
|
40
|
-
await cloudRunCommand({ project: 'org/repo', branch: 'main', wait: false });
|
|
41
|
-
expect(fetchSpy).toHaveBeenCalledTimes(1);
|
|
42
|
-
const [url, init] = fetchSpy.mock.calls[0];
|
|
43
|
-
expect(url).toBe('https://cloud.test/api/v1/runs/trigger');
|
|
44
|
-
const headers = init.headers;
|
|
45
|
-
expect(headers.Authorization).toBe('Bearer gitea-pat-123');
|
|
46
|
-
expect(JSON.parse(init.body)).toMatchObject({ project_id: 'org/repo', branch: 'main', platform: 'web' });
|
|
47
|
-
expect(process.exitCode).toBeUndefined();
|
|
48
|
-
});
|
|
49
|
-
it('exits 0 when the job reaches done', async () => {
|
|
50
|
-
const fetchSpy = mockFetchSequence([
|
|
51
|
-
{ ok: true, json: { job_id: 'job-2', status: 'queued' } },
|
|
52
|
-
{ ok: true, json: { status: 'done', run_id: 'run-2', started_at: null, completed_at: null, error_log: null } },
|
|
53
|
-
]);
|
|
54
|
-
vi.stubGlobal('fetch', fetchSpy);
|
|
55
|
-
const promise = cloudRunCommand({ project: 'org/repo', branch: 'main' });
|
|
56
|
-
await vi.advanceTimersByTimeAsync(5000);
|
|
57
|
-
await promise;
|
|
58
|
-
expect(process.exitCode).toBe(0);
|
|
59
|
-
});
|
|
60
|
-
it('exits 1 when the job reaches failed', async () => {
|
|
61
|
-
const fetchSpy = mockFetchSequence([
|
|
62
|
-
{ ok: true, json: { job_id: 'job-3', status: 'queued' } },
|
|
63
|
-
{
|
|
64
|
-
ok: true,
|
|
65
|
-
json: { status: 'failed', run_id: 'run-3', started_at: null, completed_at: null, error_log: 'boom' },
|
|
66
|
-
},
|
|
67
|
-
]);
|
|
68
|
-
vi.stubGlobal('fetch', fetchSpy);
|
|
69
|
-
const promise = cloudRunCommand({ project: 'org/repo', branch: 'main' });
|
|
70
|
-
await vi.advanceTimersByTimeAsync(5000);
|
|
71
|
-
await promise;
|
|
72
|
-
expect(process.exitCode).toBe(1);
|
|
73
|
-
});
|
|
74
|
-
it('exits 1 when the trigger request itself fails', async () => {
|
|
75
|
-
const fetchSpy = mockFetchSequence([{ ok: false, status: 401, json: { error: 'Invalid PAT' } }]);
|
|
76
|
-
vi.stubGlobal('fetch', fetchSpy);
|
|
77
|
-
await cloudRunCommand({ project: 'org/repo', branch: 'main' });
|
|
78
|
-
expect(process.exitCode).toBe(1);
|
|
79
|
-
});
|
|
80
|
-
});
|
|
81
|
-
describe('parseTimeoutMs', () => {
|
|
82
|
-
it('parses seconds, minutes, and hours', () => {
|
|
83
|
-
expect(parseTimeoutMs('30s')).toBe(30_000);
|
|
84
|
-
expect(parseTimeoutMs('30m')).toBe(30 * 60_000);
|
|
85
|
-
expect(parseTimeoutMs('2h')).toBe(2 * 3_600_000);
|
|
86
|
-
});
|
|
87
|
-
it('defaults to minutes when no unit is given', () => {
|
|
88
|
-
expect(parseTimeoutMs('10')).toBe(10 * 60_000);
|
|
89
|
-
});
|
|
90
|
-
it('falls back to 30m for unparseable input', () => {
|
|
91
|
-
expect(parseTimeoutMs('nonsense')).toBe(30 * 60_000);
|
|
92
|
-
});
|
|
93
|
-
});
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
export interface CloudRunOptions {
|
|
2
|
-
project: string;
|
|
3
|
-
projectName?: string;
|
|
4
|
-
branch?: string;
|
|
5
|
-
commit?: string;
|
|
6
|
-
platform?: string;
|
|
7
|
-
wait?: boolean;
|
|
8
|
-
timeout?: string;
|
|
9
|
-
demo?: boolean;
|
|
10
|
-
baseUrl?: string;
|
|
11
|
-
}
|
|
12
|
-
export declare function parseTimeoutMs(timeout: string): number;
|
|
13
|
-
export declare function cloudRunCommand(options: CloudRunOptions): Promise<void>;
|
|
@@ -1,120 +0,0 @@
|
|
|
1
|
-
import { execFileSync } from 'child_process';
|
|
2
|
-
import chalk from 'chalk';
|
|
3
|
-
import ora from 'ora';
|
|
4
|
-
const POLL_INTERVAL_MS = 5000;
|
|
5
|
-
const DEFAULT_TIMEOUT = '30m';
|
|
6
|
-
function detectGitRef(...args) {
|
|
7
|
-
try {
|
|
8
|
-
return execFileSync('git', args, { encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'] }).trim() || undefined;
|
|
9
|
-
}
|
|
10
|
-
catch {
|
|
11
|
-
return undefined;
|
|
12
|
-
}
|
|
13
|
-
}
|
|
14
|
-
export function parseTimeoutMs(timeout) {
|
|
15
|
-
const match = /^(\d+)(s|m|h)?$/.exec(timeout.trim());
|
|
16
|
-
if (!match)
|
|
17
|
-
return 30 * 60 * 1000;
|
|
18
|
-
const value = Number(match[1]);
|
|
19
|
-
const unit = match[2] ?? 'm';
|
|
20
|
-
const multiplier = unit === 's' ? 1000 : unit === 'h' ? 3_600_000 : 60_000;
|
|
21
|
-
return value * multiplier;
|
|
22
|
-
}
|
|
23
|
-
// Same credential path as the trigger endpoint expects: a Gitea PAT, not the
|
|
24
|
-
// dashboard's OAuth2 session — a CI runner can't complete a browser redirect.
|
|
25
|
-
// See docs/v2/cloud/git-spec-standards-and-workflow.md.
|
|
26
|
-
function requireEnv(name) {
|
|
27
|
-
const value = process.env[name];
|
|
28
|
-
if (!value) {
|
|
29
|
-
console.error(chalk.red(`Missing required environment variable: ${name}`));
|
|
30
|
-
console.error(chalk.gray('Set it as a CI secret — see docs/v2/cloud/git-spec-standards-and-workflow.md'));
|
|
31
|
-
}
|
|
32
|
-
return value;
|
|
33
|
-
}
|
|
34
|
-
export async function cloudRunCommand(options) {
|
|
35
|
-
const spectraUrl = requireEnv('SPECTRA_URL')?.replace(/\/$/, '');
|
|
36
|
-
const spectraToken = requireEnv('SPECTRA_TOKEN');
|
|
37
|
-
if (!spectraUrl || !spectraToken) {
|
|
38
|
-
process.exitCode = 1;
|
|
39
|
-
return;
|
|
40
|
-
}
|
|
41
|
-
const branch = options.branch ?? detectGitRef('rev-parse', '--abbrev-ref', 'HEAD');
|
|
42
|
-
if (!branch) {
|
|
43
|
-
console.error(chalk.red('Could not determine branch: pass --branch or run inside a git repository.'));
|
|
44
|
-
process.exitCode = 1;
|
|
45
|
-
return;
|
|
46
|
-
}
|
|
47
|
-
const commit = options.commit ?? detectGitRef('rev-parse', 'HEAD');
|
|
48
|
-
const platform = options.platform ?? 'web';
|
|
49
|
-
const wait = options.wait !== false;
|
|
50
|
-
const timeout = options.timeout ?? DEFAULT_TIMEOUT;
|
|
51
|
-
const spinner = ora(`Triggering cloud run for ${chalk.bold(options.project)}@${branch}...`).start();
|
|
52
|
-
let trigger;
|
|
53
|
-
try {
|
|
54
|
-
const res = await fetch(`${spectraUrl}/api/v1/runs/trigger`, {
|
|
55
|
-
method: 'POST',
|
|
56
|
-
headers: {
|
|
57
|
-
'Content-Type': 'application/json',
|
|
58
|
-
Authorization: `Bearer ${spectraToken}`,
|
|
59
|
-
},
|
|
60
|
-
body: JSON.stringify({
|
|
61
|
-
project_id: options.project,
|
|
62
|
-
project_name: options.projectName ?? options.project,
|
|
63
|
-
branch,
|
|
64
|
-
commit_hash: commit,
|
|
65
|
-
platform,
|
|
66
|
-
demo: options.demo ?? false,
|
|
67
|
-
base_url: options.baseUrl,
|
|
68
|
-
}),
|
|
69
|
-
});
|
|
70
|
-
if (!res.ok) {
|
|
71
|
-
const body = await res.json().catch(() => ({ error: res.statusText }));
|
|
72
|
-
throw new Error(body.error ?? `HTTP ${res.status}`);
|
|
73
|
-
}
|
|
74
|
-
trigger = (await res.json());
|
|
75
|
-
}
|
|
76
|
-
catch (err) {
|
|
77
|
-
spinner.fail(chalk.red(`Failed to trigger cloud run: ${err.message}`));
|
|
78
|
-
process.exitCode = 1;
|
|
79
|
-
return;
|
|
80
|
-
}
|
|
81
|
-
spinner.succeed(`Cloud run queued: ${chalk.cyan(trigger.job_id)}`);
|
|
82
|
-
if (!wait) {
|
|
83
|
-
console.log(chalk.gray(`Not waiting for result. Poll ${spectraUrl}/api/v1/jobs/${trigger.job_id}/status yourself.`));
|
|
84
|
-
return;
|
|
85
|
-
}
|
|
86
|
-
await waitForJob(spectraUrl, spectraToken, trigger.job_id, timeout);
|
|
87
|
-
}
|
|
88
|
-
async function waitForJob(spectraUrl, spectraToken, jobId, timeout) {
|
|
89
|
-
const spinner = ora('Waiting for run to finish...').start();
|
|
90
|
-
const deadline = Date.now() + parseTimeoutMs(timeout);
|
|
91
|
-
while (Date.now() < deadline) {
|
|
92
|
-
await new Promise((resolve) => setTimeout(resolve, POLL_INTERVAL_MS));
|
|
93
|
-
let job;
|
|
94
|
-
try {
|
|
95
|
-
const res = await fetch(`${spectraUrl}/api/v1/jobs/${jobId}/status`, {
|
|
96
|
-
headers: { Authorization: `Bearer ${spectraToken}` },
|
|
97
|
-
});
|
|
98
|
-
if (!res.ok)
|
|
99
|
-
throw new Error(`HTTP ${res.status}`);
|
|
100
|
-
job = (await res.json());
|
|
101
|
-
}
|
|
102
|
-
catch (err) {
|
|
103
|
-
spinner.text = chalk.yellow(`Poll failed, retrying: ${err.message}`);
|
|
104
|
-
continue;
|
|
105
|
-
}
|
|
106
|
-
if (job.status === 'done') {
|
|
107
|
-
spinner.succeed(chalk.green(`Run passed (run_id: ${job.run_id})`));
|
|
108
|
-
process.exitCode = 0;
|
|
109
|
-
return;
|
|
110
|
-
}
|
|
111
|
-
if (job.status === 'failed') {
|
|
112
|
-
spinner.fail(chalk.red(`Run failed (run_id: ${job.run_id})${job.error_log ? `: ${job.error_log}` : ''}`));
|
|
113
|
-
process.exitCode = 1;
|
|
114
|
-
return;
|
|
115
|
-
}
|
|
116
|
-
spinner.text = `Run status: ${job.status}`;
|
|
117
|
-
}
|
|
118
|
-
spinner.fail(chalk.red(`Timed out after ${timeout} waiting for the run to finish.`));
|
|
119
|
-
process.exitCode = 1;
|
|
120
|
-
}
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
it("should verify text and value matchers on Mobile", async () => {
|
|
2
|
-
await MatchersPage.open("text");
|
|
3
|
-
|
|
4
|
-
// Text assertions (positive and negative)
|
|
5
|
-
await MatchersPage.exactText.shouldHaveText(Fixture.playgroundData.welcomeText);
|
|
6
|
-
await MatchersPage.exactText.shouldNotHaveText("Unexpected Text");
|
|
7
|
-
|
|
8
|
-
await MatchersPage.partialText.shouldContainText("Welcome");
|
|
9
|
-
await MatchersPage.partialText.shouldNotContainText("Goodbye");
|
|
10
|
-
|
|
11
|
-
// Value assertions (positive and negative)
|
|
12
|
-
await MatchersPage.emailInput.shouldHaveValue(Fixture.playgroundData.defaultEmail);
|
|
13
|
-
await MatchersPage.emailInput.shouldNotHaveValue("wrong.user@testspectra.dev");
|
|
14
|
-
|
|
15
|
-
await MatchersPage.tokenInput.shouldContainValue("JWT_");
|
|
16
|
-
await MatchersPage.tokenInput.shouldNotContainValue("EXPIRED_SESSION");
|
|
17
|
-
});
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
it("should verify text and value matchers on Web", async () => {
|
|
2
|
-
await MatchersPage.open("text");
|
|
3
|
-
|
|
4
|
-
// Text assertions (positive and negative)
|
|
5
|
-
await MatchersPage.exactText.shouldHaveText(Fixture.playgroundData.welcomeText);
|
|
6
|
-
await MatchersPage.exactText.shouldNotHaveText("Unexpected Text");
|
|
7
|
-
|
|
8
|
-
await MatchersPage.partialText.shouldContainText("Welcome");
|
|
9
|
-
await MatchersPage.partialText.shouldNotContainText("Goodbye");
|
|
10
|
-
|
|
11
|
-
// Value assertions (positive and negative)
|
|
12
|
-
await MatchersPage.emailInput.shouldHaveValue(Fixture.playgroundData.defaultEmail);
|
|
13
|
-
await MatchersPage.emailInput.shouldNotHaveValue("wrong.user@testspectra.dev");
|
|
14
|
-
|
|
15
|
-
await MatchersPage.tokenInput.shouldContainValue("JWT_");
|
|
16
|
-
await MatchersPage.tokenInput.shouldNotContainValue("EXPIRED_SESSION");
|
|
17
|
-
});
|
/package/dist/{commands/__tests__/cloud-run.test.d.ts → linter/__tests__/anonymous-export.test.d.ts}
RENAMED
|
File without changes
|