@zohodesk/testinglibrary 0.1.9 → 0.1.12-experimental
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/.babelrc +4 -2
- package/.claude/settings.local.json +14 -0
- package/.gitlab-ci.yml +206 -0
- package/README.md +264 -1
- package/build/common/data-generator/steps/DataGenerator.spec.js +19 -0
- package/build/common/data-generator/steps/DataGeneratorStepsHelper.js +21 -0
- package/build/common/multi-actor/steps/multiActorHandling.spec.js +26 -0
- package/build/common/searchFake/helpers/rpcRequestHelper.js +52 -0
- package/build/common/searchFake/steps/searchFake.spec.js +85 -0
- package/build/core/dataGenerator/DataGenerator.js +161 -0
- package/build/core/dataGenerator/DataGeneratorError.js +60 -0
- package/build/core/dataGenerator/DataGeneratorHelper.js +121 -0
- package/build/core/dataGenerator/authenticator/Authenticator.js +37 -0
- package/build/core/dataGenerator/authenticator/CookieAuthenticator.js +48 -0
- package/build/core/dataGenerator/authenticator/JWTauthenticator.js +59 -0
- package/build/core/dataGenerator/authenticator/OAuthAuthenticator.js +26 -0
- package/build/core/dataGenerator/authenticator/OrgOAuthAuthenticator.js +26 -0
- package/build/core/dataGenerator/authenticator/cookieAuthConfig.js +11 -0
- package/build/core/jest/preprocessor/jsPreprocessor.js +2 -7
- package/build/core/jest/setup/index.js +1 -7
- package/build/core/playwright/builtInFixtures/actorContext.js +78 -0
- package/build/core/playwright/builtInFixtures/caseTimeout.js +20 -0
- package/build/core/playwright/builtInFixtures/context.js +34 -16
- package/build/core/playwright/builtInFixtures/executionContext.js +17 -0
- package/build/core/playwright/builtInFixtures/i18N.js +8 -0
- package/build/core/playwright/builtInFixtures/index.js +7 -1
- package/build/core/playwright/builtInFixtures/page.js +22 -66
- package/build/core/playwright/clear-caches.js +17 -5
- package/build/core/playwright/codegen.js +4 -21
- package/build/core/playwright/configuration/Configuration.js +25 -0
- package/build/core/playwright/configuration/ConfigurationHelper.js +45 -0
- package/build/core/playwright/configuration/UserArgs.js +12 -0
- package/build/core/playwright/constants/configConstants.js +17 -0
- package/build/core/playwright/constants/failureTagConstants.js +17 -0
- package/build/core/playwright/constants/fileMutexConfig.js +9 -0
- package/build/core/playwright/constants/reporterConstants.js +20 -0
- package/build/core/playwright/constants/retryConstants.js +8 -0
- package/build/core/playwright/custom-commands.js +1 -1
- package/build/core/playwright/env-initializer.js +28 -9
- package/build/core/playwright/fixtures.js +24 -0
- package/build/core/playwright/helpers/additionalProfiles.js +25 -0
- package/build/core/playwright/helpers/auth/accountLogin.js +4 -1
- package/build/core/playwright/helpers/auth/checkAuthCookies.js +27 -23
- package/build/core/playwright/helpers/auth/getUsers.js +92 -45
- package/build/core/playwright/helpers/auth/index.js +30 -5
- package/build/core/playwright/helpers/auth/loginDefaultStepsHelper.js +62 -0
- package/build/core/playwright/helpers/auth/loginSteps.js +40 -22
- package/build/core/playwright/helpers/browserTimeoutFactor.js +16 -0
- package/build/core/playwright/helpers/caseTimeoutResolver.js +37 -0
- package/build/core/playwright/helpers/checkAuthDirectory.js +27 -0
- package/build/core/playwright/helpers/configFileNameProvider.js +26 -5
- package/build/core/playwright/helpers/configPathResolver.js +38 -0
- package/build/core/playwright/helpers/contextFailureHandler.js +81 -0
- package/build/core/playwright/helpers/customFixturesHelper.js +58 -0
- package/build/core/playwright/helpers/failureTagClassifier.js +197 -0
- package/build/core/playwright/helpers/fileMutex.js +71 -0
- package/build/core/playwright/helpers/logCollector.js +147 -0
- package/build/core/playwright/helpers/parseUserArgs.js +2 -3
- package/build/core/playwright/helpers/runtimeLogAnnotator.js +140 -0
- package/build/core/playwright/helpers/runtimeLogPath.js +61 -0
- package/build/core/playwright/helpers/runtimeLogReader.js +54 -0
- package/build/core/playwright/helpers/thirdPartyLib.js +13 -0
- package/build/core/playwright/index.js +8 -76
- package/build/core/playwright/patterns/casePatterns.js +9 -0
- package/build/core/playwright/patterns/codePatterns.js +9 -0
- package/build/core/playwright/patterns/environmentPatterns.js +15 -0
- package/build/core/playwright/patterns/index.js +33 -0
- package/build/core/playwright/patterns/logCollectorIgnorePatterns.js +15 -0
- package/build/core/playwright/patterns/toolPatterns.js +26 -0
- package/build/core/playwright/readConfigFile.js +49 -16
- package/build/core/playwright/reporter/PlaywrightReporter.js +58 -0
- package/build/core/playwright/reporter/Reporter.js +65 -0
- package/build/core/playwright/reporter/ShardReporter.js +58 -0
- package/build/core/playwright/reporter/UnitReporter.js +27 -0
- package/build/core/playwright/reporter/helpers/mergeAbortedTests.js +78 -0
- package/build/core/playwright/runner/Runner.js +22 -0
- package/build/core/playwright/runner/RunnerHelper.js +43 -0
- package/build/core/playwright/runner/RunnerTypes.js +17 -0
- package/build/core/playwright/runner/SpawnRunner.js +93 -0
- package/build/core/playwright/setup/Project.js +35 -0
- package/build/core/playwright/setup/ProjectConfiguration.js +66 -0
- package/build/core/playwright/setup/config-creator.js +58 -40
- package/build/core/playwright/setup/config-utils.js +68 -37
- package/build/core/playwright/setup/custom-reporter.js +137 -14
- package/build/core/playwright/setup/merge-config.js +32 -0
- package/build/core/playwright/setup/qc-custom-reporter.js +342 -0
- package/build/core/playwright/spawnInheritChild.js +71 -0
- package/build/core/playwright/tagProcessor.js +69 -0
- package/build/core/playwright/test-runner.js +44 -98
- package/build/core/playwright/types.js +4 -1
- package/build/core/playwright/validateFeature.js +28 -0
- package/build/decorators.d.ts +1 -1
- package/build/decorators.js +1 -1
- package/build/index.d.ts +17 -19
- package/build/index.js +28 -6
- package/build/lib/cli.js +42 -7
- package/build/setup-folder-structure/helper.js +2 -0
- package/build/setup-folder-structure/samples/accountLogin-sample.js +19 -0
- package/build/setup-folder-structure/samples/actors-index.js +2 -0
- package/build/setup-folder-structure/samples/auth-setup-sample.js +10 -67
- package/build/setup-folder-structure/samples/editions-index.js +3 -0
- package/build/setup-folder-structure/samples/free-sample.json +25 -0
- package/build/setup-folder-structure/samples/settings.json +7 -0
- package/build/setup-folder-structure/samples/testSetup-sample.js +14 -0
- package/build/setup-folder-structure/samples/uat-config-sample.js +7 -2
- package/build/setup-folder-structure/setupProject.js +23 -5
- package/build/test/core/dataGenerator/__tests__/DataGenerator.test.js +311 -0
- package/build/test/core/dataGenerator/__tests__/DataGeneratorHelper.test.js +204 -0
- package/build/test/core/dataGenerator/__tests__/DataGeneratorResolution.test.js +126 -0
- package/build/test/core/dataGenerator/authenticator/__tests__/Authenticator.test.js +88 -0
- package/build/test/core/dataGenerator/authenticator/__tests__/JWTauthenticator.test.js +136 -0
- package/build/test/core/dataGenerator/authenticator/__tests__/OAuthAuthenticator.test.js +39 -0
- package/build/test/core/dataGenerator/authenticator/__tests__/OrgOAuthAuthenticator.test.js +39 -0
- package/build/test/core/playwright/__tests__/spawnInheritChild.test.js +148 -0
- package/build/test/core/playwright/__tests__/tagProcessor.test.js +94 -0
- package/build/test/core/playwright/__tests__/validateFeature.test.js +72 -0
- package/build/test/core/playwright/buildInFixtures/__tests__/caseTimeout.test.js +96 -0
- package/build/test/core/playwright/buildInFixtures/__tests__/executionContext.test.js +27 -0
- package/build/test/core/playwright/configuration/__tests__/Configuration.test.js +53 -0
- package/build/test/core/playwright/helpers/__tests__/additionalProfiles.test.js +45 -0
- package/build/test/core/playwright/helpers/__tests__/configFileNameProvider.test.js +75 -0
- package/build/test/core/playwright/helpers/__tests__/configPathResolver.test.js +55 -0
- package/build/test/core/playwright/helpers/__tests__/customFixturesHelper.test.js +51 -0
- package/build/test/core/playwright/helpers/__tests__/failureTagClassifier.test.js +604 -0
- package/build/test/core/playwright/helpers/__tests__/fileMutex.test.js +79 -0
- package/build/test/core/playwright/helpers/__tests__/getUsers_ListOfActors.test.js +83 -0
- package/build/test/core/playwright/helpers/__tests__/logCollector.test.js +163 -0
- package/build/test/core/playwright/helpers/__tests__/runtimeLogReader.test.js +112 -0
- package/build/test/core/playwright/helpers/auth/__tests__/checkAuthCookies.test.js +92 -0
- package/build/test/core/playwright/runner/__tests__/RunnerHelper.test.js +19 -0
- package/build/test/core/playwright/runner/__tests__/SpawnRunner.test.js +30 -0
- package/build/utils/cliArgsToObject.js +3 -0
- package/build/utils/commonUtils.js +20 -0
- package/build/utils/fileUtils.js +43 -1
- package/build/utils/logger.js +1 -30
- package/changelog.md +23 -0
- package/docs/CODE-REVIEW-AGENT.md +399 -0
- package/docs/code-review-instructions.md +157 -0
- package/jest.config.js +29 -11
- package/npm-shrinkwrap.json +14994 -4793
- package/package.json +39 -28
- package/playwright.config.js +13 -57
- package/unit_reports/unit-report.html +277 -0
- package/build/bdd-framework/cli/commands/env.js +0 -42
- package/build/bdd-framework/cli/commands/export.js +0 -47
- package/build/bdd-framework/cli/commands/test.js +0 -64
- package/build/bdd-framework/cli/index.js +0 -11
- package/build/bdd-framework/cli/options.js +0 -19
- package/build/bdd-framework/cli/worker.js +0 -13
- package/build/bdd-framework/config/configDir.js +0 -35
- package/build/bdd-framework/config/enrichReporterData.js +0 -23
- package/build/bdd-framework/config/env.js +0 -50
- package/build/bdd-framework/config/index.js +0 -94
- package/build/bdd-framework/config/lang.js +0 -14
- package/build/bdd-framework/cucumber/buildStepDefinition.js +0 -43
- package/build/bdd-framework/cucumber/createTestStep.js +0 -43
- package/build/bdd-framework/cucumber/formatter/EventDataCollector.js +0 -126
- package/build/bdd-framework/cucumber/formatter/GherkinDocumentParser.js +0 -72
- package/build/bdd-framework/cucumber/formatter/PickleParser.js +0 -25
- package/build/bdd-framework/cucumber/formatter/durationHelpers.js +0 -13
- package/build/bdd-framework/cucumber/formatter/getColorFns.js +0 -57
- package/build/bdd-framework/cucumber/formatter/index.js +0 -16
- package/build/bdd-framework/cucumber/formatter/locationHelpers.js +0 -16
- package/build/bdd-framework/cucumber/loadConfig.js +0 -17
- package/build/bdd-framework/cucumber/loadFeatures.js +0 -70
- package/build/bdd-framework/cucumber/loadSnippetBuilder.js +0 -20
- package/build/bdd-framework/cucumber/loadSteps.js +0 -47
- package/build/bdd-framework/cucumber/resolveFeaturePaths.js +0 -62
- package/build/bdd-framework/cucumber/stepArguments.js +0 -21
- package/build/bdd-framework/cucumber/types.js +0 -5
- package/build/bdd-framework/cucumber/valueChecker.js +0 -23
- package/build/bdd-framework/decorators.js +0 -18
- package/build/bdd-framework/gen/fixtures.js +0 -48
- package/build/bdd-framework/gen/formatter.js +0 -123
- package/build/bdd-framework/gen/i18n.js +0 -39
- package/build/bdd-framework/gen/index.js +0 -185
- package/build/bdd-framework/gen/testFile.js +0 -465
- package/build/bdd-framework/gen/testMeta.js +0 -60
- package/build/bdd-framework/gen/testNode.js +0 -60
- package/build/bdd-framework/gen/testPoms.js +0 -133
- package/build/bdd-framework/hooks/scenario.js +0 -130
- package/build/bdd-framework/hooks/worker.js +0 -89
- package/build/bdd-framework/index.js +0 -52
- package/build/bdd-framework/playwright/fixtureParameterNames.js +0 -93
- package/build/bdd-framework/playwright/getLocationInFile.js +0 -79
- package/build/bdd-framework/playwright/loadConfig.js +0 -42
- package/build/bdd-framework/playwright/loadUtils.js +0 -33
- package/build/bdd-framework/playwright/testTypeImpl.js +0 -61
- package/build/bdd-framework/playwright/transform.js +0 -88
- package/build/bdd-framework/playwright/types.js +0 -5
- package/build/bdd-framework/playwright/utils.js +0 -34
- package/build/bdd-framework/reporter/cucumber/base.js +0 -57
- package/build/bdd-framework/reporter/cucumber/custom.js +0 -73
- package/build/bdd-framework/reporter/cucumber/helper.js +0 -12
- package/build/bdd-framework/reporter/cucumber/html.js +0 -35
- package/build/bdd-framework/reporter/cucumber/index.js +0 -74
- package/build/bdd-framework/reporter/cucumber/json.js +0 -312
- package/build/bdd-framework/reporter/cucumber/junit.js +0 -205
- package/build/bdd-framework/reporter/cucumber/message.js +0 -20
- package/build/bdd-framework/reporter/cucumber/messagesBuilder/AttachmentMapper.js +0 -64
- package/build/bdd-framework/reporter/cucumber/messagesBuilder/Builder.js +0 -196
- package/build/bdd-framework/reporter/cucumber/messagesBuilder/GherkinDocument.js +0 -43
- package/build/bdd-framework/reporter/cucumber/messagesBuilder/GherkinDocumentClone.js +0 -52
- package/build/bdd-framework/reporter/cucumber/messagesBuilder/GherkinDocuments.js +0 -105
- package/build/bdd-framework/reporter/cucumber/messagesBuilder/Hook.js +0 -70
- package/build/bdd-framework/reporter/cucumber/messagesBuilder/Meta.js +0 -45
- package/build/bdd-framework/reporter/cucumber/messagesBuilder/Pickles.js +0 -27
- package/build/bdd-framework/reporter/cucumber/messagesBuilder/Projects.js +0 -38
- package/build/bdd-framework/reporter/cucumber/messagesBuilder/TestCase.js +0 -128
- package/build/bdd-framework/reporter/cucumber/messagesBuilder/TestCaseRun.js +0 -126
- package/build/bdd-framework/reporter/cucumber/messagesBuilder/TestCaseRunHooks.js +0 -102
- package/build/bdd-framework/reporter/cucumber/messagesBuilder/TestStepAttachments.js +0 -50
- package/build/bdd-framework/reporter/cucumber/messagesBuilder/TestStepRun.js +0 -88
- package/build/bdd-framework/reporter/cucumber/messagesBuilder/index.js +0 -30
- package/build/bdd-framework/reporter/cucumber/messagesBuilder/pwUtils.js +0 -51
- package/build/bdd-framework/reporter/cucumber/messagesBuilder/timing.js +0 -35
- package/build/bdd-framework/reporter/cucumber/messagesBuilder/types.js +0 -5
- package/build/bdd-framework/run/StepInvoker.js +0 -68
- package/build/bdd-framework/run/bddDataAttachment.js +0 -46
- package/build/bdd-framework/run/bddFixtures.js +0 -191
- package/build/bdd-framework/run/bddWorld.js +0 -79
- package/build/bdd-framework/run/bddWorldInternal.js +0 -15
- package/build/bdd-framework/snippets/index.js +0 -132
- package/build/bdd-framework/snippets/snippetSyntax.js +0 -43
- package/build/bdd-framework/snippets/snippetSyntaxDecorators.js +0 -26
- package/build/bdd-framework/snippets/snippetSyntaxTs.js +0 -18
- package/build/bdd-framework/stepDefinitions/createBdd.js +0 -66
- package/build/bdd-framework/stepDefinitions/decorators/class.js +0 -68
- package/build/bdd-framework/stepDefinitions/decorators/steps.js +0 -99
- package/build/bdd-framework/stepDefinitions/defineStep.js +0 -62
- package/build/bdd-framework/stepDefinitions/stepConfig.js +0 -24
- package/build/bdd-framework/utils/AutofillMap.js +0 -20
- package/build/bdd-framework/utils/exit.js +0 -62
- package/build/bdd-framework/utils/index.js +0 -93
- package/build/bdd-framework/utils/jsStringWrap.js +0 -44
- package/build/bdd-framework/utils/logger.js +0 -30
- package/build/bdd-framework/utils/stripAnsiEscapes.js +0 -20
- package/build/core/playwright/report-generator.js +0 -42
- package/build/core/playwright/tag-processor.js +0 -68
- package/build/setup-folder-structure/samples/authUsers-sample.json +0 -9
- package/build/setup-folder-structure/samples/env-config-sample.json +0 -21
|
@@ -0,0 +1,311 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
|
|
4
|
+
var _fs = _interopRequireDefault(require("fs"));
|
|
5
|
+
var _DataGenerator = _interopRequireDefault(require("../../../../../src/core/dataGenerator/DataGenerator"));
|
|
6
|
+
var _Authenticator = _interopRequireDefault(require("../../../../../src/core/dataGenerator/authenticator/Authenticator"));
|
|
7
|
+
jest.mock('fs');
|
|
8
|
+
jest.mock('../../../../../src/core/dataGenerator/authenticator/Authenticator');
|
|
9
|
+
const GENERATORS_JSON = {
|
|
10
|
+
generators: {
|
|
11
|
+
myGenerator: [{
|
|
12
|
+
type: 'dynamic',
|
|
13
|
+
generatorOperationId: 'applicationDriver.rpc.desk.Service.createTicket',
|
|
14
|
+
name: 'myGenerator',
|
|
15
|
+
params: {
|
|
16
|
+
status: 'Open'
|
|
17
|
+
},
|
|
18
|
+
dataPath: '$.response.body:$'
|
|
19
|
+
}]
|
|
20
|
+
}
|
|
21
|
+
};
|
|
22
|
+
function makeActorInfo(overrides = {}) {
|
|
23
|
+
return {
|
|
24
|
+
email: 'test@example.com',
|
|
25
|
+
password: 'testpass',
|
|
26
|
+
'data-generator': {
|
|
27
|
+
account: {
|
|
28
|
+
storeVariables: {
|
|
29
|
+
orgId: '12345'
|
|
30
|
+
},
|
|
31
|
+
authentications: ['org-oauth'],
|
|
32
|
+
org_oauth: {
|
|
33
|
+
clientId: 'cid',
|
|
34
|
+
clientSecret: 'sec',
|
|
35
|
+
refreshToken: 'rt'
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
},
|
|
39
|
+
...overrides
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
describe('DataGenerator.generate() — v2 payload structure', () => {
|
|
43
|
+
let dataGenerator;
|
|
44
|
+
let mockRequestPost;
|
|
45
|
+
let mockPage;
|
|
46
|
+
let testInfo;
|
|
47
|
+
beforeEach(() => {
|
|
48
|
+
dataGenerator = new _DataGenerator.default();
|
|
49
|
+
mockRequestPost = jest.fn().mockResolvedValue({
|
|
50
|
+
ok: () => true,
|
|
51
|
+
status: () => 200,
|
|
52
|
+
text: async () => '',
|
|
53
|
+
json: async () => ({
|
|
54
|
+
data: '12345',
|
|
55
|
+
logs: []
|
|
56
|
+
})
|
|
57
|
+
});
|
|
58
|
+
mockPage = {
|
|
59
|
+
request: {
|
|
60
|
+
post: mockRequestPost
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
testInfo = {
|
|
64
|
+
file: '/project/tests/ticket/my.feature',
|
|
65
|
+
title: 'suite / My Scenario'
|
|
66
|
+
};
|
|
67
|
+
_fs.default.existsSync.mockReturnValue(true);
|
|
68
|
+
_fs.default.readFileSync.mockReturnValue(JSON.stringify(GENERATORS_JSON));
|
|
69
|
+
|
|
70
|
+
// Authenticator passthrough — returns the payload untouched
|
|
71
|
+
_Authenticator.default.mockImplementation(() => ({
|
|
72
|
+
constructPayload: jest.fn().mockImplementation(payload => Promise.resolve(payload))
|
|
73
|
+
}));
|
|
74
|
+
process.env.DG_SERVICE_DOMAIN = 'https://dg-service.example.com';
|
|
75
|
+
process.env.DG_SERVICE_API_PATH = '/api/v2/data-generator/generate-data';
|
|
76
|
+
process.env.domain = 'https://app.example.com/agent';
|
|
77
|
+
process.env.DG_IAM_DOMAIN = 'https://iam.example.com';
|
|
78
|
+
});
|
|
79
|
+
afterEach(() => {
|
|
80
|
+
delete process.env.DG_SERVICE_DOMAIN;
|
|
81
|
+
delete process.env.DG_SERVICE_API_PATH;
|
|
82
|
+
delete process.env.domain;
|
|
83
|
+
delete process.env.DG_IAM_DOMAIN;
|
|
84
|
+
});
|
|
85
|
+
it('should POST to the v2 endpoint URL', async () => {
|
|
86
|
+
await dataGenerator.generate(testInfo, makeActorInfo(), 'template', 'myGenerator', 'My Scenario', [], mockPage);
|
|
87
|
+
const [url] = mockRequestPost.mock.calls[0];
|
|
88
|
+
expect(url).toBe('https://dg-service.example.com/api/v2/data-generator/generate-data');
|
|
89
|
+
});
|
|
90
|
+
it('should send scenario.name instead of scenario_name', async () => {
|
|
91
|
+
await dataGenerator.generate(testInfo, makeActorInfo(), 'template', 'myGenerator', 'My Scenario', [], mockPage);
|
|
92
|
+
const payload = mockRequestPost.mock.calls[0][1].data;
|
|
93
|
+
expect(payload.scenario).toEqual({
|
|
94
|
+
name: 'My Scenario'
|
|
95
|
+
});
|
|
96
|
+
expect(payload.scenario_name).toBeUndefined();
|
|
97
|
+
});
|
|
98
|
+
it('should include mode: "template"', async () => {
|
|
99
|
+
await dataGenerator.generate(testInfo, makeActorInfo(), 'template', 'myGenerator', 'My Scenario', [], mockPage);
|
|
100
|
+
const payload = mockRequestPost.mock.calls[0][1].data;
|
|
101
|
+
expect(payload.mode).toBe('template');
|
|
102
|
+
});
|
|
103
|
+
it('should send spec.templates instead of data_generation_templates', async () => {
|
|
104
|
+
var _payload$spec;
|
|
105
|
+
await dataGenerator.generate(testInfo, makeActorInfo(), 'template', 'myGenerator', 'My Scenario', [], mockPage);
|
|
106
|
+
const payload = mockRequestPost.mock.calls[0][1].data;
|
|
107
|
+
expect(Array.isArray((_payload$spec = payload.spec) === null || _payload$spec === void 0 ? void 0 : _payload$spec.templates)).toBe(true);
|
|
108
|
+
expect(payload.data_generation_templates).toBeUndefined();
|
|
109
|
+
});
|
|
110
|
+
it('should send environment instead of environmentDetails', async () => {
|
|
111
|
+
await dataGenerator.generate(testInfo, makeActorInfo(), 'template', 'myGenerator', 'My Scenario', [], mockPage);
|
|
112
|
+
const payload = mockRequestPost.mock.calls[0][1].data;
|
|
113
|
+
expect(payload.environment).toEqual({
|
|
114
|
+
host: 'https://app.example.com',
|
|
115
|
+
iam_url: 'https://iam.example.com'
|
|
116
|
+
});
|
|
117
|
+
expect(payload.environmentDetails).toBeUndefined();
|
|
118
|
+
});
|
|
119
|
+
it('should translate v1 generator fields to v2 inside spec.templates', async () => {
|
|
120
|
+
await dataGenerator.generate(testInfo, makeActorInfo(), 'template', 'myGenerator', 'My Scenario', [], mockPage);
|
|
121
|
+
const template = mockRequestPost.mock.calls[0][1].data.spec.templates[0];
|
|
122
|
+
expect(template.type).toBe('dynamic');
|
|
123
|
+
expect(template.generatorOperationId).toBe('applicationDriver.rpc.desk.Service.createTicket');
|
|
124
|
+
expect(template.inputs).toEqual({
|
|
125
|
+
status: 'Open'
|
|
126
|
+
});
|
|
127
|
+
expect(template.params).toBeUndefined();
|
|
128
|
+
expect(template.dataPath).toBe('$.response.body:$');
|
|
129
|
+
});
|
|
130
|
+
it('should include account with email and password from actorInfo', async () => {
|
|
131
|
+
await dataGenerator.generate(testInfo, makeActorInfo(), 'template', 'myGenerator', 'My Scenario', [], mockPage);
|
|
132
|
+
const payload = mockRequestPost.mock.calls[0][1].data;
|
|
133
|
+
expect(payload.account.email).toBe('test@example.com');
|
|
134
|
+
expect(payload.account.password).toBe('testpass');
|
|
135
|
+
expect(payload.account.storeVariables).toEqual({
|
|
136
|
+
orgId: '12345'
|
|
137
|
+
});
|
|
138
|
+
expect(payload.account.authentications).toEqual(['org-oauth']);
|
|
139
|
+
});
|
|
140
|
+
it('should return the full response from the DG service', async () => {
|
|
141
|
+
const result = await dataGenerator.generate(testInfo, makeActorInfo(), 'template', 'myGenerator', 'My Scenario', [], mockPage);
|
|
142
|
+
expect(result).toEqual({
|
|
143
|
+
data: '12345',
|
|
144
|
+
logs: []
|
|
145
|
+
});
|
|
146
|
+
});
|
|
147
|
+
it('should merge datatable values into template inputs after v1→v2 translation', async () => {
|
|
148
|
+
const dataTable = [{
|
|
149
|
+
DG_API_NAME: 'myGenerator',
|
|
150
|
+
subject: 'Test Ticket',
|
|
151
|
+
priority: 'High'
|
|
152
|
+
}];
|
|
153
|
+
await dataGenerator.generate(testInfo, makeActorInfo(), 'template', 'myGenerator', 'My Scenario', dataTable, mockPage);
|
|
154
|
+
const template = mockRequestPost.mock.calls[0][1].data.spec.templates[0];
|
|
155
|
+
expect(template.inputs.subject).toBe('Test Ticket');
|
|
156
|
+
expect(template.inputs.priority).toBe('High');
|
|
157
|
+
expect(template.inputs.status).toBe('Open');
|
|
158
|
+
});
|
|
159
|
+
it('should build v2 payload for API type generator', async () => {
|
|
160
|
+
await dataGenerator.generate(testInfo, makeActorInfo(), 'API', 'applicationDriver.rpc.desk.Service.getTicket', 'My Scenario', [], mockPage);
|
|
161
|
+
const template = mockRequestPost.mock.calls[0][1].data.spec.templates[0];
|
|
162
|
+
expect(template.type).toBe('dynamic');
|
|
163
|
+
expect(template.generatorOperationId).toBe('applicationDriver.rpc.desk.Service.getTicket');
|
|
164
|
+
expect(template.dataPath).toBe('$.response.body:$');
|
|
165
|
+
});
|
|
166
|
+
it('should throw DataGeneratorConfigurationError when data-generator config is absent', async () => {
|
|
167
|
+
const actorWithoutConfig = {
|
|
168
|
+
email: 'test@example.com',
|
|
169
|
+
profile: 'admin'
|
|
170
|
+
};
|
|
171
|
+
await expect(dataGenerator.generate(testInfo, actorWithoutConfig, 'template', 'myGenerator', 'My Scenario', [], mockPage)).rejects.toThrow('Data Generator configuration is missing');
|
|
172
|
+
});
|
|
173
|
+
it('should throw DataGeneratorConfigurationError when account is absent from data-generator config', async () => {
|
|
174
|
+
const actorWithoutAccount = {
|
|
175
|
+
email: 'test@example.com',
|
|
176
|
+
profile: 'admin',
|
|
177
|
+
'data-generator': {}
|
|
178
|
+
};
|
|
179
|
+
await expect(dataGenerator.generate(testInfo, actorWithoutAccount, 'template', 'myGenerator', 'My Scenario', [], mockPage)).rejects.toThrow('Missing "account"');
|
|
180
|
+
});
|
|
181
|
+
it('should throw when page is null and the HTTP request cannot be made', async () => {
|
|
182
|
+
await expect(dataGenerator.generate(testInfo, makeActorInfo(), 'template', 'myGenerator', 'My Scenario', [], null)).rejects.toThrow();
|
|
183
|
+
});
|
|
184
|
+
it('should throw GeneratorError when the generator name is not found in generators.json', async () => {
|
|
185
|
+
await expect(dataGenerator.generate(testInfo, makeActorInfo(), 'template', 'unknownGenerator', 'My Scenario', [], mockPage)).rejects.toThrow('Generator "unknownGenerator" could not be found');
|
|
186
|
+
});
|
|
187
|
+
it('should use portalDomain when any generatorOperationId starts with "portal."', async () => {
|
|
188
|
+
_fs.default.readFileSync.mockReturnValue(JSON.stringify({
|
|
189
|
+
generators: {
|
|
190
|
+
portalGen: [{
|
|
191
|
+
type: 'dynamic',
|
|
192
|
+
generatorOperationId: 'portal.rpc.Service.create',
|
|
193
|
+
name: 'portalGen'
|
|
194
|
+
}]
|
|
195
|
+
}
|
|
196
|
+
}));
|
|
197
|
+
process.env.portalDomain = 'https://portal.example.com/portal';
|
|
198
|
+
await dataGenerator.generate(testInfo, makeActorInfo(), 'template', 'portalGen', 'My Scenario', [], mockPage);
|
|
199
|
+
const payload = mockRequestPost.mock.calls[0][1].data;
|
|
200
|
+
expect(payload.environment.host).toBe('https://portal.example.com');
|
|
201
|
+
delete process.env.portalDomain;
|
|
202
|
+
});
|
|
203
|
+
it('should fall back to domain when operationId starts with "portal." but portalDomain is not set', async () => {
|
|
204
|
+
_fs.default.readFileSync.mockReturnValue(JSON.stringify({
|
|
205
|
+
generators: {
|
|
206
|
+
portalGen: [{
|
|
207
|
+
type: 'dynamic',
|
|
208
|
+
generatorOperationId: 'portal.rpc.Service.create',
|
|
209
|
+
name: 'portalGen'
|
|
210
|
+
}]
|
|
211
|
+
}
|
|
212
|
+
}));
|
|
213
|
+
await dataGenerator.generate(testInfo, makeActorInfo(), 'template', 'portalGen', 'My Scenario', [], mockPage);
|
|
214
|
+
const payload = mockRequestPost.mock.calls[0][1].data;
|
|
215
|
+
expect(payload.environment.host).toBe('https://app.example.com');
|
|
216
|
+
});
|
|
217
|
+
});
|
|
218
|
+
describe('DataGenerator.generate() — v1 payload structure (DG_SERVICE_API_PATH contains /v1/)', () => {
|
|
219
|
+
let dataGenerator;
|
|
220
|
+
let mockRequestPost;
|
|
221
|
+
let mockPage;
|
|
222
|
+
let testInfo;
|
|
223
|
+
beforeEach(() => {
|
|
224
|
+
dataGenerator = new _DataGenerator.default();
|
|
225
|
+
mockRequestPost = jest.fn().mockResolvedValue({
|
|
226
|
+
ok: () => true,
|
|
227
|
+
status: () => 200,
|
|
228
|
+
text: async () => '',
|
|
229
|
+
json: async () => ({
|
|
230
|
+
data: '12345',
|
|
231
|
+
logs: []
|
|
232
|
+
})
|
|
233
|
+
});
|
|
234
|
+
mockPage = {
|
|
235
|
+
request: {
|
|
236
|
+
post: mockRequestPost
|
|
237
|
+
}
|
|
238
|
+
};
|
|
239
|
+
testInfo = {
|
|
240
|
+
file: '/project/tests/ticket/my.feature',
|
|
241
|
+
title: 'suite / My Scenario'
|
|
242
|
+
};
|
|
243
|
+
_fs.default.existsSync.mockReturnValue(true);
|
|
244
|
+
_fs.default.readFileSync.mockReturnValue(JSON.stringify(GENERATORS_JSON));
|
|
245
|
+
_Authenticator.default.mockImplementation(() => ({
|
|
246
|
+
constructPayload: jest.fn().mockImplementation(payload => Promise.resolve(payload))
|
|
247
|
+
}));
|
|
248
|
+
process.env.DG_SERVICE_DOMAIN = 'https://dg-service.example.com';
|
|
249
|
+
process.env.DG_SERVICE_API_PATH = '/api/v1/data-generator/generate-data';
|
|
250
|
+
process.env.domain = 'https://app.example.com/agent';
|
|
251
|
+
process.env.DG_IAM_DOMAIN = 'https://iam.example.com';
|
|
252
|
+
});
|
|
253
|
+
afterEach(() => {
|
|
254
|
+
delete process.env.DG_SERVICE_DOMAIN;
|
|
255
|
+
delete process.env.DG_SERVICE_API_PATH;
|
|
256
|
+
delete process.env.domain;
|
|
257
|
+
delete process.env.DG_IAM_DOMAIN;
|
|
258
|
+
});
|
|
259
|
+
it('should use scenario_name instead of scenario object', async () => {
|
|
260
|
+
await dataGenerator.generate(testInfo, makeActorInfo(), 'template', 'myGenerator', 'My Scenario', [], mockPage);
|
|
261
|
+
const payload = mockRequestPost.mock.calls[0][1].data;
|
|
262
|
+
expect(payload.scenario_name).toBe('My Scenario');
|
|
263
|
+
expect(payload.scenario).toBeUndefined();
|
|
264
|
+
});
|
|
265
|
+
it('should use data_generation_templates instead of spec.templates', async () => {
|
|
266
|
+
await dataGenerator.generate(testInfo, makeActorInfo(), 'template', 'myGenerator', 'My Scenario', [], mockPage);
|
|
267
|
+
const payload = mockRequestPost.mock.calls[0][1].data;
|
|
268
|
+
expect(Array.isArray(payload.data_generation_templates)).toBe(true);
|
|
269
|
+
expect(payload.spec).toBeUndefined();
|
|
270
|
+
expect(payload.mode).toBeUndefined();
|
|
271
|
+
});
|
|
272
|
+
it('should use environmentDetails instead of environment', async () => {
|
|
273
|
+
await dataGenerator.generate(testInfo, makeActorInfo(), 'template', 'myGenerator', 'My Scenario', [], mockPage);
|
|
274
|
+
const payload = mockRequestPost.mock.calls[0][1].data;
|
|
275
|
+
expect(payload.environmentDetails).toEqual({
|
|
276
|
+
host: 'https://app.example.com',
|
|
277
|
+
iam_url: 'https://iam.example.com'
|
|
278
|
+
});
|
|
279
|
+
expect(payload.environment).toBeUndefined();
|
|
280
|
+
});
|
|
281
|
+
it('should NOT translate params to inputs in templates', async () => {
|
|
282
|
+
await dataGenerator.generate(testInfo, makeActorInfo(), 'template', 'myGenerator', 'My Scenario', [], mockPage);
|
|
283
|
+
const template = mockRequestPost.mock.calls[0][1].data.data_generation_templates[0];
|
|
284
|
+
expect(template.params).toEqual({
|
|
285
|
+
status: 'Open'
|
|
286
|
+
});
|
|
287
|
+
expect(template.inputs).toBeUndefined();
|
|
288
|
+
});
|
|
289
|
+
it('should include account with email and password from actorInfo', async () => {
|
|
290
|
+
await dataGenerator.generate(testInfo, makeActorInfo(), 'template', 'myGenerator', 'My Scenario', [], mockPage);
|
|
291
|
+
const payload = mockRequestPost.mock.calls[0][1].data;
|
|
292
|
+
expect(payload.account.email).toBe('test@example.com');
|
|
293
|
+
expect(payload.account.password).toBe('testpass');
|
|
294
|
+
});
|
|
295
|
+
it('should use portalDomain in environmentDetails when operationId starts with "portal."', async () => {
|
|
296
|
+
_fs.default.readFileSync.mockReturnValue(JSON.stringify({
|
|
297
|
+
generators: {
|
|
298
|
+
portalGen: [{
|
|
299
|
+
type: 'dynamic',
|
|
300
|
+
generatorOperationId: 'portal.rpc.Service.create',
|
|
301
|
+
name: 'portalGen'
|
|
302
|
+
}]
|
|
303
|
+
}
|
|
304
|
+
}));
|
|
305
|
+
process.env.portalDomain = 'https://portal.example.com/portal';
|
|
306
|
+
await dataGenerator.generate(testInfo, makeActorInfo(), 'template', 'portalGen', 'My Scenario', [], mockPage);
|
|
307
|
+
const payload = mockRequestPost.mock.calls[0][1].data;
|
|
308
|
+
expect(payload.environmentDetails.host).toBe('https://portal.example.com');
|
|
309
|
+
delete process.env.portalDomain;
|
|
310
|
+
});
|
|
311
|
+
});
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
|
|
4
|
+
var _path = _interopRequireDefault(require("path"));
|
|
5
|
+
var _DataGeneratorHelper = require("../../../../../src/core/dataGenerator/DataGeneratorHelper");
|
|
6
|
+
const moduleDir = _path.default.join('/repo', 'test-slices', 'uat', 'modules', 'data-generator');
|
|
7
|
+
const specFor = (generatedDir, fileName) => _path.default.join('/repo', 'test-slices', 'uat', generatedDir, 'modules', 'data-generator', 'feature-files', fileName);
|
|
8
|
+
describe('translateGeneratorsToV2', () => {
|
|
9
|
+
it('should preserve type "dynamic" unchanged', () => {
|
|
10
|
+
const result = (0, _DataGeneratorHelper.translateGeneratorsToV2)([{
|
|
11
|
+
type: 'dynamic',
|
|
12
|
+
generatorOperationId: 'some.method',
|
|
13
|
+
name: 'gen1'
|
|
14
|
+
}]);
|
|
15
|
+
expect(result[0].type).toBe('dynamic');
|
|
16
|
+
});
|
|
17
|
+
it('should preserve type "remote" unchanged', () => {
|
|
18
|
+
const result = (0, _DataGeneratorHelper.translateGeneratorsToV2)([{
|
|
19
|
+
type: 'remote',
|
|
20
|
+
generatorMethod: 'some.method',
|
|
21
|
+
inputs: {
|
|
22
|
+
a: '1'
|
|
23
|
+
}
|
|
24
|
+
}]);
|
|
25
|
+
expect(result[0].type).toBe('remote');
|
|
26
|
+
});
|
|
27
|
+
it('should preserve generatorOperationId unchanged', () => {
|
|
28
|
+
const result = (0, _DataGeneratorHelper.translateGeneratorsToV2)([{
|
|
29
|
+
type: 'dynamic',
|
|
30
|
+
generatorOperationId: 'desk.Service.create',
|
|
31
|
+
name: 'gen1'
|
|
32
|
+
}]);
|
|
33
|
+
expect(result[0].generatorOperationId).toBe('desk.Service.create');
|
|
34
|
+
});
|
|
35
|
+
it('should rename params to inputs', () => {
|
|
36
|
+
const result = (0, _DataGeneratorHelper.translateGeneratorsToV2)([{
|
|
37
|
+
type: 'dynamic',
|
|
38
|
+
generatorOperationId: 'method',
|
|
39
|
+
params: {
|
|
40
|
+
key: 'value'
|
|
41
|
+
}
|
|
42
|
+
}]);
|
|
43
|
+
expect(result[0].inputs).toEqual({
|
|
44
|
+
key: 'value'
|
|
45
|
+
});
|
|
46
|
+
expect(result[0].params).toBeUndefined();
|
|
47
|
+
});
|
|
48
|
+
it('should not overwrite existing inputs when params is also present', () => {
|
|
49
|
+
const result = (0, _DataGeneratorHelper.translateGeneratorsToV2)([{
|
|
50
|
+
type: 'dynamic',
|
|
51
|
+
generatorOperationId: 'method',
|
|
52
|
+
params: {
|
|
53
|
+
a: '1'
|
|
54
|
+
},
|
|
55
|
+
inputs: {
|
|
56
|
+
b: '2'
|
|
57
|
+
}
|
|
58
|
+
}]);
|
|
59
|
+
expect(result[0].inputs).toEqual({
|
|
60
|
+
b: '2'
|
|
61
|
+
});
|
|
62
|
+
});
|
|
63
|
+
it('should preserve dataPath unchanged', () => {
|
|
64
|
+
const result = (0, _DataGeneratorHelper.translateGeneratorsToV2)([{
|
|
65
|
+
type: 'dynamic',
|
|
66
|
+
generatorOperationId: 'method',
|
|
67
|
+
dataPath: '$.response.body:$'
|
|
68
|
+
}]);
|
|
69
|
+
expect(result[0].dataPath).toBe('$.response.body:$');
|
|
70
|
+
});
|
|
71
|
+
it('should preserve name and other custom fields', () => {
|
|
72
|
+
const result = (0, _DataGeneratorHelper.translateGeneratorsToV2)([{
|
|
73
|
+
type: 'dynamic',
|
|
74
|
+
generatorOperationId: 'method',
|
|
75
|
+
name: 'myGen',
|
|
76
|
+
customField: 'abc'
|
|
77
|
+
}]);
|
|
78
|
+
expect(result[0].name).toBe('myGen');
|
|
79
|
+
expect(result[0].customField).toBe('abc');
|
|
80
|
+
});
|
|
81
|
+
it('should translate multiple generators independently without changing type or operationId', () => {
|
|
82
|
+
const generators = [{
|
|
83
|
+
type: 'dynamic',
|
|
84
|
+
generatorOperationId: 'method.one',
|
|
85
|
+
params: {
|
|
86
|
+
x: '1'
|
|
87
|
+
},
|
|
88
|
+
name: 'gen1'
|
|
89
|
+
}, {
|
|
90
|
+
type: 'remote',
|
|
91
|
+
generatorMethod: 'method.two',
|
|
92
|
+
inputs: {
|
|
93
|
+
y: '2'
|
|
94
|
+
},
|
|
95
|
+
name: 'gen2'
|
|
96
|
+
}];
|
|
97
|
+
const result = (0, _DataGeneratorHelper.translateGeneratorsToV2)(generators);
|
|
98
|
+
expect(result[0]).toMatchObject({
|
|
99
|
+
type: 'dynamic',
|
|
100
|
+
generatorOperationId: 'method.one',
|
|
101
|
+
inputs: {
|
|
102
|
+
x: '1'
|
|
103
|
+
},
|
|
104
|
+
name: 'gen1'
|
|
105
|
+
});
|
|
106
|
+
expect(result[1]).toMatchObject({
|
|
107
|
+
type: 'remote',
|
|
108
|
+
generatorMethod: 'method.two',
|
|
109
|
+
inputs: {
|
|
110
|
+
y: '2'
|
|
111
|
+
},
|
|
112
|
+
name: 'gen2'
|
|
113
|
+
});
|
|
114
|
+
});
|
|
115
|
+
it('should handle generators with no v1 fields as a passthrough', () => {
|
|
116
|
+
const generator = {
|
|
117
|
+
type: 'remote',
|
|
118
|
+
generatorMethod: 'some.method',
|
|
119
|
+
name: 'noop'
|
|
120
|
+
};
|
|
121
|
+
const result = (0, _DataGeneratorHelper.translateGeneratorsToV2)([generator]);
|
|
122
|
+
expect(result[0]).toEqual({
|
|
123
|
+
type: 'remote',
|
|
124
|
+
generatorMethod: 'some.method',
|
|
125
|
+
name: 'noop'
|
|
126
|
+
});
|
|
127
|
+
});
|
|
128
|
+
});
|
|
129
|
+
describe('processGenerator', () => {
|
|
130
|
+
it('should return generators unchanged when no dataTable is provided', async () => {
|
|
131
|
+
const generators = [{
|
|
132
|
+
type: 'dynamic',
|
|
133
|
+
name: 'gen1'
|
|
134
|
+
}];
|
|
135
|
+
const result = await (0, _DataGeneratorHelper.processGenerator)(generators, null);
|
|
136
|
+
expect(result).toEqual(generators);
|
|
137
|
+
});
|
|
138
|
+
it('should merge matching datatable row values into generator params', async () => {
|
|
139
|
+
const generators = [{
|
|
140
|
+
type: 'dynamic',
|
|
141
|
+
name: 'gen1'
|
|
142
|
+
}];
|
|
143
|
+
const dataTable = [{
|
|
144
|
+
DG_API_NAME: 'gen1',
|
|
145
|
+
subject: 'My Ticket',
|
|
146
|
+
status: 'Open'
|
|
147
|
+
}];
|
|
148
|
+
const result = await (0, _DataGeneratorHelper.processGenerator)(generators, dataTable);
|
|
149
|
+
expect(result[0].params).toEqual({
|
|
150
|
+
subject: 'My Ticket',
|
|
151
|
+
status: 'Open'
|
|
152
|
+
});
|
|
153
|
+
});
|
|
154
|
+
it('should not merge rows whose DG_API_NAME does not match the generator name', async () => {
|
|
155
|
+
const generators = [{
|
|
156
|
+
type: 'dynamic',
|
|
157
|
+
name: 'gen1'
|
|
158
|
+
}];
|
|
159
|
+
const dataTable = [{
|
|
160
|
+
DG_API_NAME: 'gen2',
|
|
161
|
+
subject: 'My Ticket'
|
|
162
|
+
}];
|
|
163
|
+
const result = await (0, _DataGeneratorHelper.processGenerator)(generators, dataTable);
|
|
164
|
+
expect(result[0].params).toBeUndefined();
|
|
165
|
+
});
|
|
166
|
+
it('should skip empty string values from the datatable', async () => {
|
|
167
|
+
const generators = [{
|
|
168
|
+
type: 'dynamic',
|
|
169
|
+
name: 'gen1'
|
|
170
|
+
}];
|
|
171
|
+
const dataTable = [{
|
|
172
|
+
DG_API_NAME: 'gen1',
|
|
173
|
+
subject: '',
|
|
174
|
+
priority: 'High'
|
|
175
|
+
}];
|
|
176
|
+
const result = await (0, _DataGeneratorHelper.processGenerator)(generators, dataTable);
|
|
177
|
+
expect(result[0].params.subject).toBeUndefined();
|
|
178
|
+
expect(result[0].params.priority).toBe('High');
|
|
179
|
+
});
|
|
180
|
+
});
|
|
181
|
+
describe('getFeatureNameFromSpec', () => {
|
|
182
|
+
it('strips the generated spec suffix', () => {
|
|
183
|
+
expect((0, _DataGeneratorHelper.getFeatureNameFromSpec)(specFor('.features-gen', 'GetDepartment.feature.spec.js'))).toBe('GetDepartment');
|
|
184
|
+
});
|
|
185
|
+
it('keeps dots that belong to the feature name', () => {
|
|
186
|
+
expect((0, _DataGeneratorHelper.getFeatureNameFromSpec)(specFor('.features-gen', 'Get.Department.feature.spec.js'))).toBe('Get.Department');
|
|
187
|
+
});
|
|
188
|
+
});
|
|
189
|
+
describe('getGeneratorFilePath', () => {
|
|
190
|
+
it('strips the playwright-bdd output folder', async () => {
|
|
191
|
+
await expect((0, _DataGeneratorHelper.getGeneratorFilePath)(specFor('.features-gen', 'GetDepartment.feature.spec.js'))).resolves.toBe(_path.default.join(moduleDir, 'feature-files', 'GetDepartment.feature.spec.js'));
|
|
192
|
+
});
|
|
193
|
+
it('leaves a path without a generated folder untouched', async () => {
|
|
194
|
+
const plainPath = _path.default.join(moduleDir, 'feature-files', 'GetDepartment.feature.spec.js');
|
|
195
|
+
await expect((0, _DataGeneratorHelper.getGeneratorFilePath)(plainPath)).resolves.toBe(plainPath);
|
|
196
|
+
});
|
|
197
|
+
});
|
|
198
|
+
describe('getGeneratorFilePaths', () => {
|
|
199
|
+
const generatorDir = _path.default.join(moduleDir, 'data-generators');
|
|
200
|
+
it('returns the per-feature file before the legacy shared file', async () => {
|
|
201
|
+
const candidates = await (0, _DataGeneratorHelper.getGeneratorFilePaths)(specFor('.features-gen', 'GetDepartment.feature.spec.js'));
|
|
202
|
+
expect(candidates).toEqual([_path.default.join(generatorDir, 'GetDepartment.generators.json'), _path.default.join(generatorDir, 'generators.json')]);
|
|
203
|
+
});
|
|
204
|
+
});
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
|
|
4
|
+
var _fs = _interopRequireDefault(require("fs"));
|
|
5
|
+
var _path = _interopRequireDefault(require("path"));
|
|
6
|
+
var _DataGenerator = _interopRequireDefault(require("../../../../../src/core/dataGenerator/DataGenerator"));
|
|
7
|
+
var _DataGeneratorHelper = require("../../../../../src/core/dataGenerator/DataGeneratorHelper");
|
|
8
|
+
var _DataGeneratorError = require("../../../../../src/core/dataGenerator/DataGeneratorError");
|
|
9
|
+
// The framework resolves its own package name at runtime inside a consumer slice, so it is not
|
|
10
|
+
// installed here. Only the helper used by DataGenerator is needed for generator resolution.
|
|
11
|
+
jest.mock('@zohodesk/testinglibrary/helpers', () => ({
|
|
12
|
+
getUserForSelectedEditionAndProfile: jest.fn()
|
|
13
|
+
}), {
|
|
14
|
+
virtual: true
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
// Real path resolution is what these tests exercise; only the outbound call is stubbed, so
|
|
18
|
+
// generate() runs to completion and the resolved generator is observable in the request payload.
|
|
19
|
+
jest.mock('../../../../../src/core/dataGenerator/DataGeneratorHelper', () => ({
|
|
20
|
+
...jest.requireActual('../../../../../src/core/dataGenerator/DataGeneratorHelper'),
|
|
21
|
+
makeRequest: jest.fn()
|
|
22
|
+
}));
|
|
23
|
+
const moduleDir = _path.default.join('/repo', 'test-slices', 'uat', 'modules', 'data-generator');
|
|
24
|
+
const generatorDir = _path.default.join(moduleDir, 'data-generators');
|
|
25
|
+
const perFeatureFile = _path.default.join(generatorDir, 'GetDepartment.generators.json');
|
|
26
|
+
const legacyFile = _path.default.join(generatorDir, 'generators.json');
|
|
27
|
+
const testInfo = {
|
|
28
|
+
file: _path.default.join('/repo', 'test-slices', 'uat', '.features-gen', 'modules', 'data-generator', 'feature-files', 'GetDepartment.feature.spec.js')
|
|
29
|
+
};
|
|
30
|
+
const actorInfo = {
|
|
31
|
+
email: 'user@example.com',
|
|
32
|
+
password: 'secret',
|
|
33
|
+
'data-generator': {
|
|
34
|
+
account: {}
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
// The generator name is identical in both files; only `name` marks which file it came from.
|
|
39
|
+
const generatorEntry = source => [{
|
|
40
|
+
type: 'dynamic',
|
|
41
|
+
name: `CreateAccount_${source}`,
|
|
42
|
+
generatorOperationId: 'support.Account.createAccount',
|
|
43
|
+
dataPath: '$.response.body:$'
|
|
44
|
+
}];
|
|
45
|
+
const fileWithGenerator = (generatorName, source) => JSON.stringify({
|
|
46
|
+
generators: {
|
|
47
|
+
[generatorName]: generatorEntry(source)
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
// Backs fs with an in-memory file map keyed by absolute path.
|
|
52
|
+
const mockFiles = files => {
|
|
53
|
+
jest.spyOn(_fs.default, 'existsSync').mockImplementation(filePath => filePath in files);
|
|
54
|
+
jest.spyOn(_fs.default, 'readFileSync').mockImplementation(filePath => {
|
|
55
|
+
if (!(filePath in files)) {
|
|
56
|
+
throw new Error(`ENOENT: ${filePath}`);
|
|
57
|
+
}
|
|
58
|
+
return files[filePath];
|
|
59
|
+
});
|
|
60
|
+
};
|
|
61
|
+
const generate = () => new _DataGenerator.default().generate(testInfo, actorInfo, 'GENERATOR', 'CreateAccountRecord', 'scenario', null, null);
|
|
62
|
+
|
|
63
|
+
// The templates sent to the data-generator service are the generators that resolution selected.
|
|
64
|
+
const resolvedGeneratorNames = () => {
|
|
65
|
+
expect(_DataGeneratorHelper.makeRequest).toHaveBeenCalledTimes(1);
|
|
66
|
+
const [, apiPayload] = _DataGeneratorHelper.makeRequest.mock.calls[0];
|
|
67
|
+
return apiPayload.data_generation_templates.map(template => template.name);
|
|
68
|
+
};
|
|
69
|
+
describe('DataGenerator generator file resolution', () => {
|
|
70
|
+
beforeEach(() => {
|
|
71
|
+
process.env.domain = 'https://desk.example.com';
|
|
72
|
+
process.env.DG_SERVICE_API_PATH = '/api/v1/data-generator/generate-data';
|
|
73
|
+
_DataGeneratorHelper.makeRequest.mockResolvedValue({
|
|
74
|
+
data: {}
|
|
75
|
+
});
|
|
76
|
+
// Failed lookups are the expected outcome in some cases here; keep their output off the report.
|
|
77
|
+
jest.spyOn(console, 'error').mockImplementation(() => {});
|
|
78
|
+
jest.spyOn(console, 'log').mockImplementation(() => {});
|
|
79
|
+
});
|
|
80
|
+
afterEach(() => {
|
|
81
|
+
delete process.env.domain;
|
|
82
|
+
delete process.env.DG_SERVICE_API_PATH;
|
|
83
|
+
jest.restoreAllMocks();
|
|
84
|
+
});
|
|
85
|
+
it('uses the generator from the per-feature file over the legacy shared file', async () => {
|
|
86
|
+
mockFiles({
|
|
87
|
+
[perFeatureFile]: fileWithGenerator('CreateAccountRecord', 'perFeature'),
|
|
88
|
+
[legacyFile]: fileWithGenerator('CreateAccountRecord', 'legacy')
|
|
89
|
+
});
|
|
90
|
+
await generate();
|
|
91
|
+
expect(resolvedGeneratorNames()).toEqual(['CreateAccount_perFeature']);
|
|
92
|
+
expect(_fs.default.readFileSync).not.toHaveBeenCalledWith(legacyFile, 'utf8');
|
|
93
|
+
});
|
|
94
|
+
it('uses the legacy shared file when the per-feature file is absent', async () => {
|
|
95
|
+
mockFiles({
|
|
96
|
+
[legacyFile]: fileWithGenerator('CreateAccountRecord', 'legacy')
|
|
97
|
+
});
|
|
98
|
+
await generate();
|
|
99
|
+
expect(resolvedGeneratorNames()).toEqual(['CreateAccount_legacy']);
|
|
100
|
+
});
|
|
101
|
+
it('falls back to the legacy file when the per-feature file lacks the requested generator', async () => {
|
|
102
|
+
mockFiles({
|
|
103
|
+
[perFeatureFile]: fileWithGenerator('SomeOtherGenerator', 'perFeature'),
|
|
104
|
+
[legacyFile]: fileWithGenerator('CreateAccountRecord', 'legacy')
|
|
105
|
+
});
|
|
106
|
+
await generate();
|
|
107
|
+
expect(resolvedGeneratorNames()).toEqual(['CreateAccount_legacy']);
|
|
108
|
+
});
|
|
109
|
+
it('throws a GeneratorError listing every path tried when no file has the generator', async () => {
|
|
110
|
+
mockFiles({});
|
|
111
|
+
await expect(generate()).rejects.toThrow(_DataGeneratorError.GeneratorError);
|
|
112
|
+
await expect(generate()).rejects.toThrow(perFeatureFile);
|
|
113
|
+
await expect(generate()).rejects.toThrow(legacyFile);
|
|
114
|
+
expect(_DataGeneratorHelper.makeRequest).not.toHaveBeenCalled();
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
// Regression: a generator file missing the top-level "generators" key used to raise a
|
|
118
|
+
// TypeError instead of the framework's own GeneratorError.
|
|
119
|
+
it('throws a GeneratorError when a generator file has no generators key', async () => {
|
|
120
|
+
mockFiles({
|
|
121
|
+
[perFeatureFile]: JSON.stringify({})
|
|
122
|
+
});
|
|
123
|
+
await expect(generate()).rejects.toThrow(_DataGeneratorError.GeneratorError);
|
|
124
|
+
expect(_DataGeneratorHelper.makeRequest).not.toHaveBeenCalled();
|
|
125
|
+
});
|
|
126
|
+
});
|