@zohodesk/testinglibrary 0.1.9 → 0.1.16-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.
Files changed (241) hide show
  1. package/.babelrc +4 -2
  2. package/.claude/settings.local.json +14 -0
  3. package/.gitlab-ci.yml +206 -0
  4. package/README.md +264 -1
  5. package/build/common/data-generator/steps/DataGenerator.spec.js +19 -0
  6. package/build/common/data-generator/steps/DataGeneratorStepsHelper.js +21 -0
  7. package/build/common/multi-actor/steps/multiActorHandling.spec.js +26 -0
  8. package/build/common/searchFake/helpers/rpcRequestHelper.js +52 -0
  9. package/build/common/searchFake/steps/searchFake.spec.js +85 -0
  10. package/build/core/dataGenerator/DataGenerator.js +161 -0
  11. package/build/core/dataGenerator/DataGeneratorError.js +60 -0
  12. package/build/core/dataGenerator/DataGeneratorHelper.js +121 -0
  13. package/build/core/dataGenerator/authenticator/Authenticator.js +37 -0
  14. package/build/core/dataGenerator/authenticator/CookieAuthenticator.js +48 -0
  15. package/build/core/dataGenerator/authenticator/JWTauthenticator.js +59 -0
  16. package/build/core/dataGenerator/authenticator/OAuthAuthenticator.js +26 -0
  17. package/build/core/dataGenerator/authenticator/OrgOAuthAuthenticator.js +26 -0
  18. package/build/core/dataGenerator/authenticator/cookieAuthConfig.js +11 -0
  19. package/build/core/jest/preprocessor/jsPreprocessor.js +2 -7
  20. package/build/core/jest/setup/index.js +1 -7
  21. package/build/core/playwright/builtInFixtures/actorContext.js +78 -0
  22. package/build/core/playwright/builtInFixtures/caseTimeout.js +20 -0
  23. package/build/core/playwright/builtInFixtures/context.js +34 -16
  24. package/build/core/playwright/builtInFixtures/executionContext.js +17 -0
  25. package/build/core/playwright/builtInFixtures/i18N.js +8 -0
  26. package/build/core/playwright/builtInFixtures/index.js +7 -1
  27. package/build/core/playwright/builtInFixtures/page.js +22 -66
  28. package/build/core/playwright/clear-caches.js +17 -5
  29. package/build/core/playwright/codegen.js +4 -21
  30. package/build/core/playwright/configuration/Configuration.js +25 -0
  31. package/build/core/playwright/configuration/ConfigurationHelper.js +45 -0
  32. package/build/core/playwright/configuration/UserArgs.js +12 -0
  33. package/build/core/playwright/constants/configConstants.js +17 -0
  34. package/build/core/playwright/constants/failureTagConstants.js +17 -0
  35. package/build/core/playwright/constants/fileMutexConfig.js +9 -0
  36. package/build/core/playwright/constants/reporterConstants.js +20 -0
  37. package/build/core/playwright/constants/retryConstants.js +8 -0
  38. package/build/core/playwright/custom-commands.js +1 -1
  39. package/build/core/playwright/env-initializer.js +28 -9
  40. package/build/core/playwright/fixtures.js +24 -0
  41. package/build/core/playwright/helpers/additionalProfiles.js +25 -0
  42. package/build/core/playwright/helpers/auth/accountLogin.js +4 -1
  43. package/build/core/playwright/helpers/auth/checkAuthCookies.js +27 -23
  44. package/build/core/playwright/helpers/auth/getUsers.js +92 -45
  45. package/build/core/playwright/helpers/auth/index.js +30 -5
  46. package/build/core/playwright/helpers/auth/loginDefaultStepsHelper.js +62 -0
  47. package/build/core/playwright/helpers/auth/loginSteps.js +40 -22
  48. package/build/core/playwright/helpers/browserTimeoutFactor.js +16 -0
  49. package/build/core/playwright/helpers/caseTimeoutResolver.js +37 -0
  50. package/build/core/playwright/helpers/checkAuthDirectory.js +27 -0
  51. package/build/core/playwright/helpers/configFileNameProvider.js +26 -5
  52. package/build/core/playwright/helpers/configPathResolver.js +38 -0
  53. package/build/core/playwright/helpers/contextFailureHandler.js +81 -0
  54. package/build/core/playwright/helpers/customFixturesHelper.js +58 -0
  55. package/build/core/playwright/helpers/failureTagClassifier.js +197 -0
  56. package/build/core/playwright/helpers/fileMutex.js +71 -0
  57. package/build/core/playwright/helpers/logCollector.js +147 -0
  58. package/build/core/playwright/helpers/parseUserArgs.js +2 -3
  59. package/build/core/playwright/helpers/runtimeLogAnnotator.js +140 -0
  60. package/build/core/playwright/helpers/runtimeLogPath.js +61 -0
  61. package/build/core/playwright/helpers/runtimeLogReader.js +54 -0
  62. package/build/core/playwright/helpers/thirdPartyLib.js +13 -0
  63. package/build/core/playwright/index.js +8 -76
  64. package/build/core/playwright/patterns/casePatterns.js +9 -0
  65. package/build/core/playwright/patterns/codePatterns.js +9 -0
  66. package/build/core/playwright/patterns/environmentPatterns.js +15 -0
  67. package/build/core/playwright/patterns/index.js +33 -0
  68. package/build/core/playwright/patterns/logCollectorIgnorePatterns.js +15 -0
  69. package/build/core/playwright/patterns/toolPatterns.js +26 -0
  70. package/build/core/playwright/readConfigFile.js +49 -16
  71. package/build/core/playwright/reporter/PlaywrightReporter.js +58 -0
  72. package/build/core/playwright/reporter/Reporter.js +60 -0
  73. package/build/core/playwright/reporter/ShardReporter.js +62 -0
  74. package/build/core/playwright/reporter/UnitReporter.js +27 -0
  75. package/build/core/playwright/reporter/helpers/mergeAbortedTests.js +78 -0
  76. package/build/core/playwright/runCommand.js +71 -0
  77. package/build/core/playwright/runner/Runner.js +22 -0
  78. package/build/core/playwright/runner/RunnerHelper.js +43 -0
  79. package/build/core/playwright/runner/RunnerTypes.js +17 -0
  80. package/build/core/playwright/runner/SpawnRunner.js +93 -0
  81. package/build/core/playwright/setup/Project.js +35 -0
  82. package/build/core/playwright/setup/ProjectConfiguration.js +66 -0
  83. package/build/core/playwright/setup/config-creator.js +58 -40
  84. package/build/core/playwright/setup/config-utils.js +68 -37
  85. package/build/core/playwright/setup/custom-reporter.js +137 -14
  86. package/build/core/playwright/setup/merge-config.js +32 -0
  87. package/build/core/playwright/setup/qc-custom-reporter.js +342 -0
  88. package/build/core/playwright/tagProcessor.js +69 -0
  89. package/build/core/playwright/test-runner.js +44 -98
  90. package/build/core/playwright/types.js +4 -1
  91. package/build/core/playwright/validateFeature.js +28 -0
  92. package/build/decorators.d.ts +1 -1
  93. package/build/decorators.js +1 -1
  94. package/build/index.d.ts +17 -19
  95. package/build/index.js +28 -6
  96. package/build/lib/cli.js +42 -7
  97. package/build/setup-folder-structure/helper.js +2 -0
  98. package/build/setup-folder-structure/samples/accountLogin-sample.js +19 -0
  99. package/build/setup-folder-structure/samples/actors-index.js +2 -0
  100. package/build/setup-folder-structure/samples/auth-setup-sample.js +10 -67
  101. package/build/setup-folder-structure/samples/editions-index.js +3 -0
  102. package/build/setup-folder-structure/samples/free-sample.json +25 -0
  103. package/build/setup-folder-structure/samples/settings.json +7 -0
  104. package/build/setup-folder-structure/samples/testSetup-sample.js +14 -0
  105. package/build/setup-folder-structure/samples/uat-config-sample.js +7 -2
  106. package/build/setup-folder-structure/setupProject.js +23 -5
  107. package/build/test/core/dataGenerator/__tests__/DataGenerator.test.js +311 -0
  108. package/build/test/core/dataGenerator/__tests__/DataGeneratorHelper.test.js +204 -0
  109. package/build/test/core/dataGenerator/__tests__/DataGeneratorResolution.test.js +126 -0
  110. package/build/test/core/dataGenerator/authenticator/__tests__/Authenticator.test.js +88 -0
  111. package/build/test/core/dataGenerator/authenticator/__tests__/JWTauthenticator.test.js +136 -0
  112. package/build/test/core/dataGenerator/authenticator/__tests__/OAuthAuthenticator.test.js +39 -0
  113. package/build/test/core/dataGenerator/authenticator/__tests__/OrgOAuthAuthenticator.test.js +39 -0
  114. package/build/test/core/playwright/__tests__/runCommand.test.js +148 -0
  115. package/build/test/core/playwright/__tests__/tagProcessor.test.js +94 -0
  116. package/build/test/core/playwright/__tests__/validateFeature.test.js +72 -0
  117. package/build/test/core/playwright/buildInFixtures/__tests__/caseTimeout.test.js +96 -0
  118. package/build/test/core/playwright/buildInFixtures/__tests__/executionContext.test.js +27 -0
  119. package/build/test/core/playwright/configuration/__tests__/Configuration.test.js +53 -0
  120. package/build/test/core/playwright/helpers/__tests__/additionalProfiles.test.js +45 -0
  121. package/build/test/core/playwright/helpers/__tests__/configFileNameProvider.test.js +75 -0
  122. package/build/test/core/playwright/helpers/__tests__/configPathResolver.test.js +55 -0
  123. package/build/test/core/playwright/helpers/__tests__/customFixturesHelper.test.js +51 -0
  124. package/build/test/core/playwright/helpers/__tests__/failureTagClassifier.test.js +604 -0
  125. package/build/test/core/playwright/helpers/__tests__/fileMutex.test.js +79 -0
  126. package/build/test/core/playwright/helpers/__tests__/getUsers_ListOfActors.test.js +83 -0
  127. package/build/test/core/playwright/helpers/__tests__/logCollector.test.js +163 -0
  128. package/build/test/core/playwright/helpers/__tests__/runtimeLogReader.test.js +112 -0
  129. package/build/test/core/playwright/helpers/auth/__tests__/checkAuthCookies.test.js +120 -0
  130. package/build/test/core/playwright/runner/__tests__/RunnerHelper.test.js +19 -0
  131. package/build/test/core/playwright/runner/__tests__/SpawnRunner.test.js +30 -0
  132. package/build/utils/cliArgsToObject.js +3 -0
  133. package/build/utils/commonUtils.js +20 -0
  134. package/build/utils/fileUtils.js +43 -1
  135. package/build/utils/logger.js +1 -30
  136. package/changelog.md +23 -0
  137. package/docs/CODE-REVIEW-AGENT.md +399 -0
  138. package/docs/code-review-instructions.md +157 -0
  139. package/jest.config.js +29 -11
  140. package/npm-shrinkwrap.json +13478 -4778
  141. package/package.json +39 -28
  142. package/playwright.config.js +13 -57
  143. package/unit_reports/unit-report.html +277 -0
  144. package/build/bdd-framework/cli/commands/env.js +0 -42
  145. package/build/bdd-framework/cli/commands/export.js +0 -47
  146. package/build/bdd-framework/cli/commands/test.js +0 -64
  147. package/build/bdd-framework/cli/index.js +0 -11
  148. package/build/bdd-framework/cli/options.js +0 -19
  149. package/build/bdd-framework/cli/worker.js +0 -13
  150. package/build/bdd-framework/config/configDir.js +0 -35
  151. package/build/bdd-framework/config/enrichReporterData.js +0 -23
  152. package/build/bdd-framework/config/env.js +0 -50
  153. package/build/bdd-framework/config/index.js +0 -94
  154. package/build/bdd-framework/config/lang.js +0 -14
  155. package/build/bdd-framework/cucumber/buildStepDefinition.js +0 -43
  156. package/build/bdd-framework/cucumber/createTestStep.js +0 -43
  157. package/build/bdd-framework/cucumber/formatter/EventDataCollector.js +0 -126
  158. package/build/bdd-framework/cucumber/formatter/GherkinDocumentParser.js +0 -72
  159. package/build/bdd-framework/cucumber/formatter/PickleParser.js +0 -25
  160. package/build/bdd-framework/cucumber/formatter/durationHelpers.js +0 -13
  161. package/build/bdd-framework/cucumber/formatter/getColorFns.js +0 -57
  162. package/build/bdd-framework/cucumber/formatter/index.js +0 -16
  163. package/build/bdd-framework/cucumber/formatter/locationHelpers.js +0 -16
  164. package/build/bdd-framework/cucumber/loadConfig.js +0 -17
  165. package/build/bdd-framework/cucumber/loadFeatures.js +0 -70
  166. package/build/bdd-framework/cucumber/loadSnippetBuilder.js +0 -20
  167. package/build/bdd-framework/cucumber/loadSteps.js +0 -47
  168. package/build/bdd-framework/cucumber/resolveFeaturePaths.js +0 -62
  169. package/build/bdd-framework/cucumber/stepArguments.js +0 -21
  170. package/build/bdd-framework/cucumber/types.js +0 -5
  171. package/build/bdd-framework/cucumber/valueChecker.js +0 -23
  172. package/build/bdd-framework/decorators.js +0 -18
  173. package/build/bdd-framework/gen/fixtures.js +0 -48
  174. package/build/bdd-framework/gen/formatter.js +0 -123
  175. package/build/bdd-framework/gen/i18n.js +0 -39
  176. package/build/bdd-framework/gen/index.js +0 -185
  177. package/build/bdd-framework/gen/testFile.js +0 -465
  178. package/build/bdd-framework/gen/testMeta.js +0 -60
  179. package/build/bdd-framework/gen/testNode.js +0 -60
  180. package/build/bdd-framework/gen/testPoms.js +0 -133
  181. package/build/bdd-framework/hooks/scenario.js +0 -130
  182. package/build/bdd-framework/hooks/worker.js +0 -89
  183. package/build/bdd-framework/index.js +0 -52
  184. package/build/bdd-framework/playwright/fixtureParameterNames.js +0 -93
  185. package/build/bdd-framework/playwright/getLocationInFile.js +0 -79
  186. package/build/bdd-framework/playwright/loadConfig.js +0 -42
  187. package/build/bdd-framework/playwright/loadUtils.js +0 -33
  188. package/build/bdd-framework/playwright/testTypeImpl.js +0 -61
  189. package/build/bdd-framework/playwright/transform.js +0 -88
  190. package/build/bdd-framework/playwright/types.js +0 -5
  191. package/build/bdd-framework/playwright/utils.js +0 -34
  192. package/build/bdd-framework/reporter/cucumber/base.js +0 -57
  193. package/build/bdd-framework/reporter/cucumber/custom.js +0 -73
  194. package/build/bdd-framework/reporter/cucumber/helper.js +0 -12
  195. package/build/bdd-framework/reporter/cucumber/html.js +0 -35
  196. package/build/bdd-framework/reporter/cucumber/index.js +0 -74
  197. package/build/bdd-framework/reporter/cucumber/json.js +0 -312
  198. package/build/bdd-framework/reporter/cucumber/junit.js +0 -205
  199. package/build/bdd-framework/reporter/cucumber/message.js +0 -20
  200. package/build/bdd-framework/reporter/cucumber/messagesBuilder/AttachmentMapper.js +0 -64
  201. package/build/bdd-framework/reporter/cucumber/messagesBuilder/Builder.js +0 -196
  202. package/build/bdd-framework/reporter/cucumber/messagesBuilder/GherkinDocument.js +0 -43
  203. package/build/bdd-framework/reporter/cucumber/messagesBuilder/GherkinDocumentClone.js +0 -52
  204. package/build/bdd-framework/reporter/cucumber/messagesBuilder/GherkinDocuments.js +0 -105
  205. package/build/bdd-framework/reporter/cucumber/messagesBuilder/Hook.js +0 -70
  206. package/build/bdd-framework/reporter/cucumber/messagesBuilder/Meta.js +0 -45
  207. package/build/bdd-framework/reporter/cucumber/messagesBuilder/Pickles.js +0 -27
  208. package/build/bdd-framework/reporter/cucumber/messagesBuilder/Projects.js +0 -38
  209. package/build/bdd-framework/reporter/cucumber/messagesBuilder/TestCase.js +0 -128
  210. package/build/bdd-framework/reporter/cucumber/messagesBuilder/TestCaseRun.js +0 -126
  211. package/build/bdd-framework/reporter/cucumber/messagesBuilder/TestCaseRunHooks.js +0 -102
  212. package/build/bdd-framework/reporter/cucumber/messagesBuilder/TestStepAttachments.js +0 -50
  213. package/build/bdd-framework/reporter/cucumber/messagesBuilder/TestStepRun.js +0 -88
  214. package/build/bdd-framework/reporter/cucumber/messagesBuilder/index.js +0 -30
  215. package/build/bdd-framework/reporter/cucumber/messagesBuilder/pwUtils.js +0 -51
  216. package/build/bdd-framework/reporter/cucumber/messagesBuilder/timing.js +0 -35
  217. package/build/bdd-framework/reporter/cucumber/messagesBuilder/types.js +0 -5
  218. package/build/bdd-framework/run/StepInvoker.js +0 -68
  219. package/build/bdd-framework/run/bddDataAttachment.js +0 -46
  220. package/build/bdd-framework/run/bddFixtures.js +0 -191
  221. package/build/bdd-framework/run/bddWorld.js +0 -79
  222. package/build/bdd-framework/run/bddWorldInternal.js +0 -15
  223. package/build/bdd-framework/snippets/index.js +0 -132
  224. package/build/bdd-framework/snippets/snippetSyntax.js +0 -43
  225. package/build/bdd-framework/snippets/snippetSyntaxDecorators.js +0 -26
  226. package/build/bdd-framework/snippets/snippetSyntaxTs.js +0 -18
  227. package/build/bdd-framework/stepDefinitions/createBdd.js +0 -66
  228. package/build/bdd-framework/stepDefinitions/decorators/class.js +0 -68
  229. package/build/bdd-framework/stepDefinitions/decorators/steps.js +0 -99
  230. package/build/bdd-framework/stepDefinitions/defineStep.js +0 -62
  231. package/build/bdd-framework/stepDefinitions/stepConfig.js +0 -24
  232. package/build/bdd-framework/utils/AutofillMap.js +0 -20
  233. package/build/bdd-framework/utils/exit.js +0 -62
  234. package/build/bdd-framework/utils/index.js +0 -93
  235. package/build/bdd-framework/utils/jsStringWrap.js +0 -44
  236. package/build/bdd-framework/utils/logger.js +0 -30
  237. package/build/bdd-framework/utils/stripAnsiEscapes.js +0 -20
  238. package/build/core/playwright/report-generator.js +0 -42
  239. package/build/core/playwright/tag-processor.js +0 -68
  240. package/build/setup-folder-structure/samples/authUsers-sample.json +0 -9
  241. package/build/setup-folder-structure/samples/env-config-sample.json +0 -21
@@ -0,0 +1,88 @@
1
+ "use strict";
2
+
3
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4
+ var _Authenticator = _interopRequireDefault(require("../../../../../../src/core/dataGenerator/authenticator/Authenticator"));
5
+ describe('Authenticator', () => {
6
+ it('should throw an error when an unknown authentication type is present', async () => {
7
+ const authenticator = new _Authenticator.default();
8
+ const apiPayload = {
9
+ account: {
10
+ name: 'sample'
11
+ }
12
+ };
13
+ const actorInfo = {
14
+ 'data-generator': {
15
+ account: {
16
+ authentications: ['apikey', 'basic']
17
+ }
18
+ }
19
+ };
20
+ await expect(authenticator.constructPayload(apiPayload, actorInfo)).rejects.toThrow('Unknown authentication type: "apikey"');
21
+ });
22
+ it('should route iam-oauth2-schema authentication and merge oauth2 config into payload', async () => {
23
+ const authenticator = new _Authenticator.default();
24
+ const apiPayload = {
25
+ account: {}
26
+ };
27
+ const actorInfo = {
28
+ 'data-generator': {
29
+ account: {
30
+ authentications: ['iam-oauth2-schema'],
31
+ oauth2: {
32
+ client_id: 'client_1',
33
+ client_secret: 'secret_1'
34
+ }
35
+ }
36
+ }
37
+ };
38
+ const result = await authenticator.constructPayload(apiPayload, actorInfo);
39
+ expect(result.account.oauth2).toEqual({
40
+ client_id: 'client_1',
41
+ client_secret: 'secret_1'
42
+ });
43
+ });
44
+ it('should treat authentication values case-insensitively and deduplicate them', async () => {
45
+ const authenticator = new _Authenticator.default();
46
+ const apiPayload = {
47
+ account: {}
48
+ };
49
+ const actorInfo = {
50
+ 'data-generator': {
51
+ account: {
52
+ authentications: ['IAM-OAUTH2-SCHEMA', 'iam-oauth2-schema', 'Iam-Oauth2-Schema'],
53
+ oauth2: {
54
+ scope: 'read'
55
+ }
56
+ }
57
+ }
58
+ };
59
+ const result = await authenticator.constructPayload(apiPayload, actorInfo);
60
+ expect(result.account.oauth2).toEqual({
61
+ scope: 'read'
62
+ });
63
+ });
64
+ it('should apply only the first supported authentication type', async () => {
65
+ const authenticator = new _Authenticator.default();
66
+ const apiPayload = {
67
+ account: {}
68
+ };
69
+ const actorInfo = {
70
+ 'data-generator': {
71
+ account: {
72
+ authentications: ['iam-oauth2-schema', 'org-oauth'],
73
+ oauth2: {
74
+ client_id: 'oauth-client'
75
+ },
76
+ org_oauth: {
77
+ org_id: 'org-101'
78
+ }
79
+ }
80
+ }
81
+ };
82
+ const result = await authenticator.constructPayload(apiPayload, actorInfo);
83
+ expect(result.account.oauth2).toEqual({
84
+ client_id: 'oauth-client'
85
+ });
86
+ expect(result.account.org_oauth).toBeUndefined();
87
+ });
88
+ });
@@ -0,0 +1,136 @@
1
+ "use strict";
2
+
3
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4
+ var _JWTauthenticator = _interopRequireDefault(require("../../../../../../src/core/dataGenerator/authenticator/JWTauthenticator"));
5
+ describe('JWTauthenticator', () => {
6
+ let requestPostMock;
7
+ let page;
8
+ beforeEach(() => {
9
+ requestPostMock = jest.fn();
10
+ page = {
11
+ request: {
12
+ post: requestPostMock
13
+ }
14
+ };
15
+ process.env.DG_JWT_AUTH_URL = 'https://jwt-auth.example.com';
16
+ process.env.DG_DOMAIN_URL = 'https://domain.example.com';
17
+ process.env.DG_JWT_AUTHENTICATOR_API = 'https://authenticator.example.com/jwtToken';
18
+ });
19
+ afterEach(() => {
20
+ delete process.env.DG_JWT_AUTH_URL;
21
+ delete process.env.DG_DOMAIN_URL;
22
+ delete process.env.DG_JWT_AUTHENTICATOR_API;
23
+ });
24
+ it('should throw when jwt-oauth config is missing', async () => {
25
+ const jwtAuthenticator = new _JWTauthenticator.default();
26
+ const apiPayload = {
27
+ account: {}
28
+ };
29
+ const actorInfo = {
30
+ email: 'user@example.com',
31
+ 'data-generator': {
32
+ account: {}
33
+ }
34
+ };
35
+ await expect(jwtAuthenticator.constructPayload(apiPayload, actorInfo, page)).rejects.toThrow('JWT authentication failed: "jwt-oauth" is missing in actor configuration');
36
+ expect(requestPostMock).not.toHaveBeenCalled();
37
+ });
38
+ it('should fetch jwt access token and set it in authHeaders', async () => {
39
+ requestPostMock.mockResolvedValue({
40
+ ok: () => true,
41
+ status: () => 200,
42
+ text: async () => '',
43
+ json: async () => ({
44
+ access_token: 'access-token-123'
45
+ })
46
+ });
47
+ const jwtAuthenticator = new _JWTauthenticator.default();
48
+ const apiPayload = {
49
+ account: {}
50
+ };
51
+ const actorInfo = {
52
+ email: 'user.one@example.com',
53
+ 'data-generator': {
54
+ account: {
55
+ 'jwt-oauth': {
56
+ jwt_secret: 'jwt-secret',
57
+ response_type: 'token',
58
+ client_id: '12345.client-id',
59
+ token_url: 'https://token.example.com/12345/oauth'
60
+ }
61
+ }
62
+ }
63
+ };
64
+ const result = await jwtAuthenticator.constructPayload(apiPayload, actorInfo, page);
65
+ expect(requestPostMock).toHaveBeenCalledTimes(1);
66
+ expect(requestPostMock).toHaveBeenCalledWith('https://authenticator.example.com/jwtToken', expect.objectContaining({
67
+ headers: {
68
+ 'Content-Type': 'application/json'
69
+ },
70
+ data: expect.objectContaining({
71
+ user_token: encodeURIComponent('user.one@example.com'),
72
+ jwt_secret: 'jwt-secret',
73
+ jwt_auth_url: 'https://jwt-auth.example.com',
74
+ response_type: 'token',
75
+ client_id: '12345.client-id',
76
+ token_url: 'https://token.example.com/12345/oauth',
77
+ domain_url: 'https://domain.example.com'
78
+ })
79
+ }));
80
+ expect(result.account.authHeaders.Authorization).toBe('Zoho-oauthtoken access-token-123');
81
+ });
82
+ it('should throw a descriptive error when authenticator API returns non-ok response', async () => {
83
+ requestPostMock.mockResolvedValue({
84
+ ok: () => false,
85
+ status: () => 500,
86
+ text: async () => 'internal error',
87
+ json: async () => ({})
88
+ });
89
+ const jwtAuthenticator = new _JWTauthenticator.default();
90
+ const apiPayload = {
91
+ account: {}
92
+ };
93
+ const actorInfo = {
94
+ email: 'user@example.com',
95
+ 'data-generator': {
96
+ account: {
97
+ 'jwt-oauth': {
98
+ jwt_secret: 'jwt-secret',
99
+ response_type: 'token',
100
+ client_id: '12345.client-id',
101
+ token_url: 'https://token.example.com/12345/oauth'
102
+ }
103
+ }
104
+ }
105
+ };
106
+ await expect(jwtAuthenticator.constructPayload(apiPayload, actorInfo, page)).rejects.toThrow('JWT authenticator error! status: 500, body: internal error');
107
+ });
108
+ it('should throw when authenticator response has no access_token', async () => {
109
+ requestPostMock.mockResolvedValue({
110
+ ok: () => true,
111
+ status: () => 200,
112
+ text: async () => '',
113
+ json: async () => ({
114
+ token_type: 'Bearer'
115
+ })
116
+ });
117
+ const jwtAuthenticator = new _JWTauthenticator.default();
118
+ const apiPayload = {
119
+ account: {}
120
+ };
121
+ const actorInfo = {
122
+ email: 'user@example.com',
123
+ 'data-generator': {
124
+ account: {
125
+ 'jwt-oauth': {
126
+ jwt_secret: 'jwt-secret',
127
+ response_type: 'token',
128
+ client_id: '12345.client-id',
129
+ token_url: 'https://token.example.com/12345/oauth'
130
+ }
131
+ }
132
+ }
133
+ };
134
+ await expect(jwtAuthenticator.constructPayload(apiPayload, actorInfo, page)).rejects.toThrow('JWT authenticator did not return access_token');
135
+ });
136
+ });
@@ -0,0 +1,39 @@
1
+ "use strict";
2
+
3
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4
+ var _OAuthAuthenticator = _interopRequireDefault(require("../../../../../../src/core/dataGenerator/authenticator/OAuthAuthenticator"));
5
+ describe('OAuthAuthenticator', () => {
6
+ it('should assign oauth2 from actor info into payload account', async () => {
7
+ const oauthAuthenticator = new _OAuthAuthenticator.default();
8
+ const apiPayload = {
9
+ account: {}
10
+ };
11
+ const actorInfo = {
12
+ 'data-generator': {
13
+ account: {
14
+ oauth2: {
15
+ client_id: 'new-client',
16
+ scope: 'tickets.read'
17
+ }
18
+ }
19
+ }
20
+ };
21
+ const result = await oauthAuthenticator.constructPayload(apiPayload, actorInfo);
22
+ expect(result.account.oauth2).toEqual({
23
+ client_id: 'new-client',
24
+ scope: 'tickets.read'
25
+ });
26
+ });
27
+ it('should throw when oauth2 is absent in actor configuration', async () => {
28
+ const oauthAuthenticator = new _OAuthAuthenticator.default();
29
+ const apiPayload = {
30
+ account: {}
31
+ };
32
+ const actorInfo = {
33
+ 'data-generator': {
34
+ account: {}
35
+ }
36
+ };
37
+ await expect(oauthAuthenticator.constructPayload(apiPayload, actorInfo)).rejects.toThrow('OAuth2 authentication failed: "oauth2" is missing in actor configuration');
38
+ });
39
+ });
@@ -0,0 +1,39 @@
1
+ "use strict";
2
+
3
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4
+ var _OrgOAuthAuthenticator = _interopRequireDefault(require("../../../../../../src/core/dataGenerator/authenticator/OrgOAuthAuthenticator"));
5
+ describe('OrgOAuthAuthenticator', () => {
6
+ it('should assign org_oauth from actor info into payload account', async () => {
7
+ const orgOAuthAuthenticator = new _OrgOAuthAuthenticator.default();
8
+ const apiPayload = {
9
+ account: {}
10
+ };
11
+ const actorInfo = {
12
+ 'data-generator': {
13
+ account: {
14
+ org_oauth: {
15
+ org_id: 'org-1001',
16
+ region: 'us'
17
+ }
18
+ }
19
+ }
20
+ };
21
+ const result = await orgOAuthAuthenticator.constructPayload(apiPayload, actorInfo);
22
+ expect(result.account.org_oauth).toEqual({
23
+ org_id: 'org-1001',
24
+ region: 'us'
25
+ });
26
+ });
27
+ it('should throw when org_oauth is absent in actor configuration', async () => {
28
+ const orgOAuthAuthenticator = new _OrgOAuthAuthenticator.default();
29
+ const apiPayload = {
30
+ account: {}
31
+ };
32
+ const actorInfo = {
33
+ 'data-generator': {
34
+ account: {}
35
+ }
36
+ };
37
+ await expect(orgOAuthAuthenticator.constructPayload(apiPayload, actorInfo)).rejects.toThrow('OrgOAuth authentication failed: "org_oauth" is missing in actor configuration');
38
+ });
39
+ });
@@ -0,0 +1,148 @@
1
+ "use strict";
2
+
3
+ var _events = require("events");
4
+ var _child_process = require("child_process");
5
+ var _logger = require("../../../../utils/logger");
6
+ var _runCommand = require("../../../../core/playwright/runCommand");
7
+ jest.mock('child_process');
8
+ jest.mock('../../../../utils/logger', () => ({
9
+ __esModule: true,
10
+ Logger: {
11
+ log: jest.fn(),
12
+ SUCCESS_TYPE: 'success',
13
+ FAILURE_TYPE: 'failure',
14
+ INFO_TYPE: 'info'
15
+ }
16
+ }));
17
+ describe('runCommand', () => {
18
+ let childProcess;
19
+ let processHandlers;
20
+ let processOnSpy;
21
+ let processExitSpy;
22
+ beforeEach(() => {
23
+ childProcess = new _events.EventEmitter();
24
+ childProcess.kill = jest.fn();
25
+ _child_process.spawn.mockReturnValue(childProcess);
26
+ processHandlers = {};
27
+ processOnSpy = jest.spyOn(process, 'on').mockImplementation((event, handler) => {
28
+ processHandlers[event] = handler;
29
+ return process;
30
+ });
31
+ processExitSpy = jest.spyOn(process, 'exit').mockImplementation(() => {});
32
+ });
33
+ afterEach(() => {
34
+ processOnSpy.mockRestore();
35
+ processExitSpy.mockRestore();
36
+ });
37
+ it('should spawn the child with the parent stdio and environment', () => {
38
+ (0, _runCommand.runCommand)('playwright', ['test']);
39
+ expect(_child_process.spawn).toHaveBeenCalledWith('playwright', ['test'], {
40
+ stdio: 'inherit',
41
+ env: {
42
+ ...process.env
43
+ }
44
+ });
45
+ });
46
+ it('should resolve and log the success message when the child exits cleanly', async () => {
47
+ const promise = (0, _runCommand.runCommand)('playwright', ['test'], {
48
+ successMessage: 'Test Ran Successfully'
49
+ });
50
+ childProcess.emit('exit', 0, null);
51
+ await expect(promise).resolves.toBeUndefined();
52
+ expect(_logger.Logger.log).toHaveBeenCalledWith(_logger.Logger.SUCCESS_TYPE, 'Test Ran Successfully');
53
+ });
54
+ it('should reject with the default message when the child exits with a failure', async () => {
55
+ const promise = (0, _runCommand.runCommand)('playwright', ['test']);
56
+ childProcess.emit('exit', 1, 'SIGTERM');
57
+ await expect(promise).rejects.toBe('Child Process Exited with Code 1 and Signal SIGTERM');
58
+ });
59
+ it('should reject with the caller message when bddgen exits with a failure', async () => {
60
+ const promise = (0, _runCommand.runCommand)('node', ['bddgen'], {
61
+ failureMessage: code => `BddGen exited with code ${code}`
62
+ });
63
+ childProcess.emit('exit', 2, null);
64
+ await expect(promise).rejects.toBe('BddGen exited with code 2');
65
+ });
66
+ it('should reject when the child fails to spawn', async () => {
67
+ const error = new Error('spawn ENOENT');
68
+ const promise = (0, _runCommand.runCommand)('playwright', ['test']);
69
+ childProcess.emit('error', error);
70
+ await expect(promise).rejects.toBe(error);
71
+ expect(_logger.Logger.log).toHaveBeenCalledWith(_logger.Logger.FAILURE_TYPE, error);
72
+ });
73
+ it('should not listen on the parent process unless the caller asks for it', () => {
74
+ (0, _runCommand.runCommand)('node', ['bddgen']);
75
+ expect(processHandlers.exit).toBeUndefined();
76
+ expect(processHandlers.SIGINT).toBeUndefined();
77
+ });
78
+ it('should kill the child and reject when the run is interrupted', async () => {
79
+ const promise = (0, _runCommand.runCommand)('playwright', ['test'], {
80
+ killOnParentExit: true
81
+ });
82
+ processHandlers.SIGINT();
83
+ await expect(promise).rejects.toBe('Cleaning up...');
84
+ expect(childProcess.kill).toHaveBeenCalled();
85
+ });
86
+ it('should kill the child and reject when the parent exits', async () => {
87
+ const promise = (0, _runCommand.runCommand)('playwright', ['test'], {
88
+ killOnParentExit: true
89
+ });
90
+ processHandlers.exit();
91
+ await expect(promise).rejects.toBe('Terminating Playwright Process...');
92
+ expect(childProcess.kill).toHaveBeenCalled();
93
+ });
94
+ it('should log the failure and exit when a CLI child exits with a failure', () => {
95
+ (0, _runCommand.runCommand)('playwright', ['merge-reports'], {
96
+ exitOnSuccess: true
97
+ });
98
+ childProcess.emit('exit', 1, 'SIGTERM');
99
+ expect(_logger.Logger.log).toHaveBeenCalledWith(_logger.Logger.FAILURE_TYPE, 'Child Process Exited with Code 1 and Signal SIGTERM');
100
+ expect(processExitSpy).toHaveBeenCalledWith(1);
101
+ });
102
+ it('should not listen for SIGINT unless the caller owns the child lifetime', () => {
103
+ (0, _runCommand.runCommand)('playwright', ['merge-reports'], {
104
+ successMessage: 'Blob Reports Merged Successfully',
105
+ exitOnSuccess: true
106
+ });
107
+ expect(processHandlers.SIGINT).toBeUndefined();
108
+ expect(processHandlers.exit).toBeUndefined();
109
+ });
110
+ it('should exit with the child when the caller owns the process lifetime', () => {
111
+ (0, _runCommand.runCommand)('playwright', ['show-report'], {
112
+ exitOnSuccess: true
113
+ });
114
+ childProcess.emit('exit', 0, null);
115
+ expect(processExitSpy).toHaveBeenCalledWith(0);
116
+ });
117
+ it('should propagate the child exit code when merge-reports completes', () => {
118
+ (0, _runCommand.runCommand)('playwright', ['merge-reports'], {
119
+ successMessage: 'Blob Reports Merged Successfully',
120
+ exitOnSuccess: true
121
+ });
122
+ childProcess.emit('exit', 0, null);
123
+ expect(_logger.Logger.log).toHaveBeenCalledWith(_logger.Logger.SUCCESS_TYPE, 'Blob Reports Merged Successfully');
124
+ expect(processExitSpy).toHaveBeenCalledWith(0);
125
+ });
126
+ it('should log spawn errors without rejecting a CLI command', () => {
127
+ const error = new Error('spawn ENOENT');
128
+ (0, _runCommand.runCommand)('playwright', ['codegen'], {
129
+ exitOnSuccess: true
130
+ });
131
+ childProcess.emit('error', error);
132
+ expect(_logger.Logger.log).toHaveBeenCalledWith(_logger.Logger.FAILURE_TYPE, error);
133
+ expect(processExitSpy).not.toHaveBeenCalled();
134
+ });
135
+ it('should kill the child on SIGINT and on the parent exit', () => {
136
+ (0, _runCommand.runCommand)('playwright', ['show-report'], {
137
+ exitOnSuccess: true,
138
+ killOnParentExit: true
139
+ });
140
+ processHandlers.exit();
141
+ expect(childProcess.kill).toHaveBeenCalledTimes(1);
142
+ expect(_logger.Logger.log).toHaveBeenCalledWith(_logger.Logger.INFO_TYPE, 'Terminating Playwright Process...');
143
+ processHandlers.SIGINT();
144
+ expect(childProcess.kill).toHaveBeenCalledTimes(2);
145
+ expect(_logger.Logger.log).toHaveBeenCalledWith(_logger.Logger.INFO_TYPE, 'Cleaning up...');
146
+ expect(processExitSpy).toHaveBeenCalled();
147
+ });
148
+ });
@@ -0,0 +1,94 @@
1
+ "use strict";
2
+
3
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4
+ var _tagProcessor = _interopRequireDefault(require("../../../../../src/core/playwright/tagProcessor"));
5
+ var _logger = require("../../../../utils/logger");
6
+ jest.mock('../../../../utils/logger');
7
+ describe('TagProcessor', () => {
8
+ const editionOrder = ['edition1', 'edition2', 'edition3', 'edition4'];
9
+ beforeEach(() => {
10
+ jest.clearAllMocks();
11
+ });
12
+ test('should return tagArgs if no edition is provided', () => {
13
+ const tagProcessor = new _tagProcessor.default(editionOrder);
14
+ const userArgs = {
15
+ tags: 'tag1',
16
+ edition: null
17
+ };
18
+ const result = tagProcessor.processTags(userArgs);
19
+ expect(result).toBe('tag1');
20
+ });
21
+ test('should handle a single edition with <= operator', () => {
22
+ const tagProcessor = new _tagProcessor.default(editionOrder);
23
+ const userArgs = {
24
+ tags: 'tag1',
25
+ edition: '<=edition2'
26
+ };
27
+ const result = tagProcessor.processTags(userArgs);
28
+ expect(result).toBe('tag1 and not (@edition_edition3 or @edition_edition4)');
29
+ });
30
+ test('should handle a single edition with >= operator', () => {
31
+ const tagProcessor = new _tagProcessor.default(editionOrder);
32
+ const userArgs = {
33
+ tags: 'tag1',
34
+ edition: '>=edition2'
35
+ };
36
+ const result = tagProcessor.processTags(userArgs);
37
+ expect(result).toBe('tag1 and not (@edition_edition1)');
38
+ });
39
+ test('should handle a single edition with < operator', () => {
40
+ const tagProcessor = new _tagProcessor.default(editionOrder);
41
+ const userArgs = {
42
+ tags: 'tag1',
43
+ edition: '<edition3'
44
+ };
45
+ const result = tagProcessor.processTags(userArgs);
46
+ expect(result).toBe('tag1 and not (@edition_edition3 or @edition_edition4)');
47
+ });
48
+ test('should handle a single edition with > operator', () => {
49
+ const tagProcessor = new _tagProcessor.default(editionOrder);
50
+ const userArgs = {
51
+ tags: 'tag1',
52
+ edition: '>edition1'
53
+ };
54
+ const result = tagProcessor.processTags(userArgs);
55
+ expect(result).toBe('tag1 and not (@edition_edition1)');
56
+ });
57
+ test('should handle a single edition with no operator', () => {
58
+ const tagProcessor = new _tagProcessor.default(editionOrder);
59
+ const userArgs = {
60
+ tags: 'tag1',
61
+ edition: 'edition2'
62
+ };
63
+ const result = tagProcessor.processTags(userArgs);
64
+ expect(result).toBe('tag1 and not (@edition_edition1 or @edition_edition3 or @edition_edition4)');
65
+ });
66
+ test('should log a message if edition is not found', () => {
67
+ const tagProcessor = new _tagProcessor.default(editionOrder);
68
+ const userArgs = {
69
+ tags: 'tag1',
70
+ edition: 'nonexistentEdition'
71
+ };
72
+ const result = tagProcessor.processTags(userArgs);
73
+ expect(result).toBe('tag1');
74
+ expect(_logger.Logger.log).toHaveBeenCalledWith(_logger.Logger.INFO_TYPE, expect.stringContaining('No matching editions for nonexistentEdition found.'));
75
+ });
76
+ test('should handle multiple editions', () => {
77
+ const tagProcessor = new _tagProcessor.default(editionOrder);
78
+ const userArgs = {
79
+ tags: 'tag1',
80
+ edition: 'edition1,edition3'
81
+ };
82
+ const result = tagProcessor.processTags(userArgs);
83
+ expect(result).toBe('tag1 and not (@edition_edition2 or @edition_edition4)');
84
+ });
85
+ test('should build tags correctly when tags are empty', () => {
86
+ const tagProcessor = new _tagProcessor.default(editionOrder);
87
+ const userArgs = {
88
+ tags: '',
89
+ edition: 'edition1'
90
+ };
91
+ const result = tagProcessor.processTags(userArgs);
92
+ expect(result).toBe('not (@edition_edition2 or @edition_edition3 or @edition_edition4)');
93
+ });
94
+ });
@@ -0,0 +1,72 @@
1
+ "use strict";
2
+
3
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4
+ var _validateFeature = _interopRequireDefault(require("../../../../core/playwright/validateFeature"));
5
+ var _parseUserArgs = _interopRequireDefault(require("../../../../core/playwright/helpers/parseUserArgs"));
6
+ var _readConfigFile = require("../../../../core/playwright/readConfigFile");
7
+ var _tagProcessor = _interopRequireDefault(require("../../../../core/playwright/tagProcessor"));
8
+ var _testRunner = require("../../../../core/playwright/test-runner");
9
+ var _logger = require("../../../../utils/logger");
10
+ jest.mock('../../../../core/playwright/helpers/parseUserArgs', () => ({
11
+ __esModule: true,
12
+ default: jest.fn()
13
+ }));
14
+ jest.mock('../../../../core/playwright/readConfigFile');
15
+ jest.mock('../../../../core/playwright/tagProcessor');
16
+ jest.mock('../../../../core/playwright/test-runner', () => ({
17
+ __esModule: true,
18
+ runPreprocessing: jest.fn()
19
+ }));
20
+ jest.mock('../../../../utils/logger', () => ({
21
+ __esModule: true,
22
+ Logger: {
23
+ log: jest.fn(),
24
+ SUCCESS_TYPE: 'success',
25
+ FAILURE_TYPE: 'failure'
26
+ }
27
+ }));
28
+ describe('validateFeatureFiles', () => {
29
+ let tagProcessorInstance;
30
+ beforeEach(() => {
31
+ jest.clearAllMocks();
32
+ tagProcessorInstance = {
33
+ processTags: jest.fn()
34
+ };
35
+ _tagProcessor.default.mockImplementation(() => tagProcessorInstance);
36
+ });
37
+ test('runPreprocessing with correct arguments and log success', async () => {
38
+ const mockUserArgs = {
39
+ mode: 'dev'
40
+ };
41
+ _parseUserArgs.default.mockReturnValue(mockUserArgs);
42
+ const mockConfig = {
43
+ editionOrder: ["beta", "enterprice"]
44
+ };
45
+ _readConfigFile.generateConfigFromFile.mockReturnValue(mockConfig);
46
+ _readConfigFile.isUserConfigFileAvailable.mockReturnValue(true);
47
+ const mockTagArgs = ['@beta_admin'];
48
+ tagProcessorInstance.processTags.mockReturnValue(mockTagArgs);
49
+ _testRunner.runPreprocessing.mockResolvedValueOnce();
50
+ await (0, _validateFeature.default)();
51
+ expect(_parseUserArgs.default).toHaveBeenCalled();
52
+ expect(_readConfigFile.generateConfigFromFile).toHaveBeenCalled();
53
+ expect(_readConfigFile.isUserConfigFileAvailable).toHaveBeenCalled();
54
+ expect(tagProcessorInstance.processTags).toHaveBeenCalledWith(mockUserArgs);
55
+ expect(_testRunner.runPreprocessing).toHaveBeenCalledWith(mockTagArgs, expect.stringContaining('config-creator.js'));
56
+ expect(_logger.Logger.log).toHaveBeenCalledWith(_logger.Logger.SUCCESS_TYPE, 'Feature files validated successfully.');
57
+ });
58
+ test('runPreprocessing with playwright conf', async () => {
59
+ const mockTagArgs = ['@beta_admin'];
60
+ tagProcessorInstance.processTags.mockReturnValue(mockTagArgs);
61
+ _readConfigFile.isUserConfigFileAvailable.mockReturnValue(false);
62
+ _testRunner.runPreprocessing.mockResolvedValueOnce();
63
+ await (0, _validateFeature.default)();
64
+ expect(_testRunner.runPreprocessing).toHaveBeenCalledWith(mockTagArgs, expect.stringContaining('playwright.config.js'));
65
+ });
66
+ test('error when runPreprocessing fails', async () => {
67
+ const mockError = new Error('Test error');
68
+ _testRunner.runPreprocessing.mockRejectedValueOnce(mockError);
69
+ await await (0, _validateFeature.default)();
70
+ expect(_logger.Logger.log).toHaveBeenCalledWith(_logger.Logger.FAILURE_TYPE, `Error while validating the feature files - ${mockError}`);
71
+ });
72
+ });