@open-mercato/core 0.4.9-develop-e55592929f → 0.4.9-develop-97d4cca067

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 (86) hide show
  1. package/dist/helpers/integration/api.js +66 -0
  2. package/dist/helpers/integration/api.js.map +7 -0
  3. package/dist/helpers/integration/apiKeysFixtures.js +16 -0
  4. package/dist/helpers/integration/apiKeysFixtures.js.map +7 -0
  5. package/dist/helpers/integration/attachmentsFixtures.js +61 -0
  6. package/dist/helpers/integration/attachmentsFixtures.js.map +7 -0
  7. package/dist/helpers/integration/auth.js +190 -0
  8. package/dist/helpers/integration/auth.js.map +7 -0
  9. package/dist/helpers/integration/authFixtures.js +39 -0
  10. package/dist/helpers/integration/authFixtures.js.map +7 -0
  11. package/dist/helpers/integration/authUi.js +31 -0
  12. package/dist/helpers/integration/authUi.js.map +7 -0
  13. package/dist/helpers/integration/businessRulesFixtures.js +40 -0
  14. package/dist/helpers/integration/businessRulesFixtures.js.map +7 -0
  15. package/dist/helpers/integration/catalogFixtures.js +49 -0
  16. package/dist/helpers/integration/catalogFixtures.js.map +7 -0
  17. package/dist/helpers/integration/crmFixtures.js +91 -0
  18. package/dist/helpers/integration/crmFixtures.js.map +7 -0
  19. package/dist/helpers/integration/currenciesFixtures.js +39 -0
  20. package/dist/helpers/integration/currenciesFixtures.js.map +7 -0
  21. package/dist/helpers/integration/dictionariesFixtures.js +16 -0
  22. package/dist/helpers/integration/dictionariesFixtures.js.map +7 -0
  23. package/dist/helpers/integration/featureTogglesFixtures.js +23 -0
  24. package/dist/helpers/integration/featureTogglesFixtures.js.map +7 -0
  25. package/dist/helpers/integration/generalFixtures.js +56 -0
  26. package/dist/helpers/integration/generalFixtures.js.map +7 -0
  27. package/dist/helpers/integration/inboxFixtures.js +67 -0
  28. package/dist/helpers/integration/inboxFixtures.js.map +7 -0
  29. package/dist/helpers/integration/notificationsFixtures.js +48 -0
  30. package/dist/helpers/integration/notificationsFixtures.js.map +7 -0
  31. package/dist/helpers/integration/salesFixtures.js +63 -0
  32. package/dist/helpers/integration/salesFixtures.js.map +7 -0
  33. package/dist/helpers/integration/salesUi.js +827 -0
  34. package/dist/helpers/integration/salesUi.js.map +7 -0
  35. package/dist/helpers/integration/sseEventCollector.js +27 -0
  36. package/dist/helpers/integration/sseEventCollector.js.map +7 -0
  37. package/dist/helpers/integration/staffFixtures.js +47 -0
  38. package/dist/helpers/integration/staffFixtures.js.map +7 -0
  39. package/dist/modules/auth/lib/setup-app.js +17 -1
  40. package/dist/modules/auth/lib/setup-app.js.map +2 -2
  41. package/dist/testing/integration/api.js +2 -0
  42. package/dist/testing/integration/api.js.map +7 -0
  43. package/dist/testing/integration/auth.js +2 -0
  44. package/dist/testing/integration/auth.js.map +7 -0
  45. package/dist/testing/integration/authFixtures.js +2 -0
  46. package/dist/testing/integration/authFixtures.js.map +7 -0
  47. package/dist/testing/integration/authUi.js +2 -0
  48. package/dist/testing/integration/authUi.js.map +7 -0
  49. package/dist/testing/integration/crmFixtures.js +2 -0
  50. package/dist/testing/integration/crmFixtures.js.map +7 -0
  51. package/dist/testing/integration/dictionariesFixtures.js +2 -0
  52. package/dist/testing/integration/dictionariesFixtures.js.map +7 -0
  53. package/dist/testing/integration/generalFixtures.js +2 -0
  54. package/dist/testing/integration/generalFixtures.js.map +7 -0
  55. package/dist/testing/integration/index.js +48 -0
  56. package/dist/testing/integration/index.js.map +7 -0
  57. package/package.json +11 -3
  58. package/src/helpers/integration/api.ts +87 -0
  59. package/src/helpers/integration/apiKeysFixtures.ts +17 -0
  60. package/src/helpers/integration/attachmentsFixtures.ts +114 -0
  61. package/src/helpers/integration/auth.ts +208 -0
  62. package/src/helpers/integration/authFixtures.ts +52 -0
  63. package/src/helpers/integration/authUi.ts +33 -0
  64. package/src/helpers/integration/businessRulesFixtures.ts +53 -0
  65. package/src/helpers/integration/catalogFixtures.ts +73 -0
  66. package/src/helpers/integration/crmFixtures.ts +132 -0
  67. package/src/helpers/integration/currenciesFixtures.ts +49 -0
  68. package/src/helpers/integration/dictionariesFixtures.ts +17 -0
  69. package/src/helpers/integration/featureTogglesFixtures.ts +28 -0
  70. package/src/helpers/integration/generalFixtures.ts +71 -0
  71. package/src/helpers/integration/inboxFixtures.ts +94 -0
  72. package/src/helpers/integration/notificationsFixtures.ts +67 -0
  73. package/src/helpers/integration/salesFixtures.ts +89 -0
  74. package/src/helpers/integration/salesUi.ts +936 -0
  75. package/src/helpers/integration/sseEventCollector.ts +30 -0
  76. package/src/helpers/integration/staffFixtures.ts +61 -0
  77. package/src/modules/auth/lib/setup-app.ts +22 -0
  78. package/src/testing/integration/api.ts +1 -0
  79. package/src/testing/integration/auth.ts +1 -0
  80. package/src/testing/integration/authFixtures.ts +1 -0
  81. package/src/testing/integration/authUi.ts +1 -0
  82. package/src/testing/integration/crmFixtures.ts +1 -0
  83. package/src/testing/integration/dictionariesFixtures.ts +1 -0
  84. package/src/testing/integration/generalFixtures.ts +1 -0
  85. package/src/testing/integration/index.ts +22 -0
  86. package/tsconfig.json +3 -0
@@ -0,0 +1,91 @@
1
+ import { expect } from "@playwright/test";
2
+ import { apiRequest } from "./api.js";
3
+ import { readJsonSafe } from "./generalFixtures.js";
4
+ import { readJsonSafe as readJsonSafe2 } from "./generalFixtures.js";
5
+ function isRecord(value) {
6
+ return typeof value === "object" && value !== null;
7
+ }
8
+ function findStringByKeys(value, keys) {
9
+ if (!isRecord(value)) return null;
10
+ for (const key of keys) {
11
+ const candidate = value[key];
12
+ if (typeof candidate === "string" && candidate.trim().length > 0) {
13
+ return candidate.trim();
14
+ }
15
+ }
16
+ for (const nested of Object.values(value)) {
17
+ if (Array.isArray(nested)) continue;
18
+ const found = findStringByKeys(nested, keys);
19
+ if (found) return found;
20
+ }
21
+ return null;
22
+ }
23
+ async function createEntity(request, token, path, data, idKeys) {
24
+ const response = await apiRequest(request, "POST", path, { token, data });
25
+ const payload = await readJsonSafe(response);
26
+ expect(response.ok(), `Failed POST ${path}: ${response.status()}`).toBeTruthy();
27
+ const id = findStringByKeys(payload, idKeys);
28
+ expect(id, `No id in ${path} response`).toBeTruthy();
29
+ return id;
30
+ }
31
+ async function createCompanyFixture(request, token, displayName) {
32
+ return createEntity(request, token, "/api/customers/companies", { displayName }, ["id", "entityId", "companyId"]);
33
+ }
34
+ async function createPersonFixture(request, token, input) {
35
+ const data = {
36
+ firstName: input.firstName,
37
+ lastName: input.lastName,
38
+ displayName: input.displayName
39
+ };
40
+ if (input.companyEntityId) {
41
+ data.companyEntityId = input.companyEntityId;
42
+ }
43
+ return createEntity(request, token, "/api/customers/people", data, ["id", "entityId", "personId"]);
44
+ }
45
+ async function createDealFixture(request, token, input) {
46
+ const data = { title: input.title };
47
+ if (input.companyIds?.length) data.companyIds = input.companyIds;
48
+ if (input.personIds?.length) data.personIds = input.personIds;
49
+ if (input.pipelineId) data.pipelineId = input.pipelineId;
50
+ if (input.pipelineStageId) data.pipelineStageId = input.pipelineStageId;
51
+ if (input.valueAmount !== void 0) data.valueAmount = input.valueAmount;
52
+ if (input.valueCurrency) data.valueCurrency = input.valueCurrency;
53
+ return createEntity(request, token, "/api/customers/deals", data, ["dealId", "id", "entityId"]);
54
+ }
55
+ async function createPipelineFixture(request, token, input) {
56
+ const data = { name: input.name };
57
+ if (input.isDefault !== void 0) data.isDefault = input.isDefault;
58
+ return createEntity(request, token, "/api/customers/pipelines", data, ["id", "pipelineId"]);
59
+ }
60
+ async function createPipelineStageFixture(request, token, input) {
61
+ const data = { pipelineId: input.pipelineId, label: input.label };
62
+ if (input.order !== void 0) data.order = input.order;
63
+ return createEntity(request, token, "/api/customers/pipeline-stages", data, ["id", "stageId"]);
64
+ }
65
+ async function deleteEntityByBody(request, token, path, id) {
66
+ if (!token || !id) return;
67
+ try {
68
+ await apiRequest(request, "DELETE", path, { token, data: { id } });
69
+ } catch {
70
+ return;
71
+ }
72
+ }
73
+ async function deleteEntityIfExists(request, token, path, id) {
74
+ if (!token || !id) return;
75
+ try {
76
+ await apiRequest(request, "DELETE", `${path}?id=${encodeURIComponent(id)}`, { token });
77
+ } catch {
78
+ return;
79
+ }
80
+ }
81
+ export {
82
+ createCompanyFixture,
83
+ createDealFixture,
84
+ createPersonFixture,
85
+ createPipelineFixture,
86
+ createPipelineStageFixture,
87
+ deleteEntityByBody,
88
+ deleteEntityIfExists,
89
+ readJsonSafe2 as readJsonSafe
90
+ };
91
+ //# sourceMappingURL=crmFixtures.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../src/helpers/integration/crmFixtures.ts"],
4
+ "sourcesContent": ["import { expect, type APIRequestContext } from '@playwright/test';\nimport { apiRequest } from './api';\nimport { readJsonSafe } from './generalFixtures';\n\ntype JsonRecord = Record<string, unknown>;\n\nexport { readJsonSafe } from './generalFixtures';\n\nfunction isRecord(value: unknown): value is JsonRecord {\n return typeof value === 'object' && value !== null;\n}\n\nfunction findStringByKeys(value: unknown, keys: readonly string[]): string | null {\n if (!isRecord(value)) return null;\n\n for (const key of keys) {\n const candidate = value[key];\n if (typeof candidate === 'string' && candidate.trim().length > 0) {\n return candidate.trim();\n }\n }\n\n for (const nested of Object.values(value)) {\n if (Array.isArray(nested)) continue;\n const found = findStringByKeys(nested, keys);\n if (found) return found;\n }\n\n return null;\n}\n\nasync function createEntity(\n request: APIRequestContext,\n token: string,\n path: string,\n data: Record<string, unknown>,\n idKeys: readonly string[],\n): Promise<string> {\n const response = await apiRequest(request, 'POST', path, { token, data });\n const payload = await readJsonSafe(response);\n expect(response.ok(), `Failed POST ${path}: ${response.status()}`).toBeTruthy();\n const id = findStringByKeys(payload, idKeys);\n expect(id, `No id in ${path} response`).toBeTruthy();\n return id as string;\n}\n\nexport async function createCompanyFixture(\n request: APIRequestContext,\n token: string,\n displayName: string,\n): Promise<string> {\n return createEntity(request, token, '/api/customers/companies', { displayName }, ['id', 'entityId', 'companyId']);\n}\n\nexport async function createPersonFixture(\n request: APIRequestContext,\n token: string,\n input: { firstName: string; lastName: string; displayName: string; companyEntityId?: string },\n): Promise<string> {\n const data: Record<string, unknown> = {\n firstName: input.firstName,\n lastName: input.lastName,\n displayName: input.displayName,\n };\n if (input.companyEntityId) {\n data.companyEntityId = input.companyEntityId;\n }\n return createEntity(request, token, '/api/customers/people', data, ['id', 'entityId', 'personId']);\n}\n\nexport async function createDealFixture(\n request: APIRequestContext,\n token: string,\n input: { title: string; companyIds?: string[]; personIds?: string[]; pipelineId?: string; pipelineStageId?: string; valueAmount?: number; valueCurrency?: string },\n): Promise<string> {\n const data: Record<string, unknown> = { title: input.title };\n if (input.companyIds?.length) data.companyIds = input.companyIds;\n if (input.personIds?.length) data.personIds = input.personIds;\n if (input.pipelineId) data.pipelineId = input.pipelineId;\n if (input.pipelineStageId) data.pipelineStageId = input.pipelineStageId;\n if (input.valueAmount !== undefined) data.valueAmount = input.valueAmount;\n if (input.valueCurrency) data.valueCurrency = input.valueCurrency;\n return createEntity(request, token, '/api/customers/deals', data, ['dealId', 'id', 'entityId']);\n}\n\nexport async function createPipelineFixture(\n request: APIRequestContext,\n token: string,\n input: { name: string; isDefault?: boolean },\n): Promise<string> {\n const data: Record<string, unknown> = { name: input.name };\n if (input.isDefault !== undefined) data.isDefault = input.isDefault;\n return createEntity(request, token, '/api/customers/pipelines', data, ['id', 'pipelineId']);\n}\n\nexport async function createPipelineStageFixture(\n request: APIRequestContext,\n token: string,\n input: { pipelineId: string; label: string; order?: number },\n): Promise<string> {\n const data: Record<string, unknown> = { pipelineId: input.pipelineId, label: input.label };\n if (input.order !== undefined) data.order = input.order;\n return createEntity(request, token, '/api/customers/pipeline-stages', data, ['id', 'stageId']);\n}\n\nexport async function deleteEntityByBody(\n request: APIRequestContext,\n token: string | null,\n path: string,\n id: string | null,\n): Promise<void> {\n if (!token || !id) return;\n try {\n await apiRequest(request, 'DELETE', path, { token, data: { id } });\n } catch {\n return;\n }\n}\n\nexport async function deleteEntityIfExists(\n request: APIRequestContext,\n token: string | null,\n path: string,\n id: string | null,\n): Promise<void> {\n if (!token || !id) return;\n try {\n await apiRequest(request, 'DELETE', `${path}?id=${encodeURIComponent(id)}`, { token });\n } catch {\n return;\n }\n}\n"],
5
+ "mappings": "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",
6
+ "names": ["readJsonSafe"]
7
+ }
@@ -0,0 +1,39 @@
1
+ import { expect } from "@playwright/test";
2
+ import { apiRequest } from "./api.js";
3
+ import { getTokenContext } from "./generalFixtures.js";
4
+ async function createCurrencyFixture(request, token, input) {
5
+ const { organizationId, tenantId } = getTokenContext(token);
6
+ const response = await apiRequest(request, "POST", "/api/currencies/currencies", {
7
+ token,
8
+ data: { organizationId, tenantId, code: input.code, name: input.name, symbol: input.symbol ?? null }
9
+ });
10
+ expect(response.ok(), `Failed to create currency fixture: ${response.status()}`).toBeTruthy();
11
+ const body = await response.json();
12
+ expect(typeof body.id === "string" && body.id.length > 0).toBeTruthy();
13
+ return body.id;
14
+ }
15
+ async function createFetchConfigFixture(request, token, input) {
16
+ const response = await apiRequest(request, "POST", "/api/currencies/fetch-configs", {
17
+ token,
18
+ data: input
19
+ });
20
+ expect(response.ok(), `Failed to create fetch config fixture: ${response.status()}`).toBeTruthy();
21
+ const body = await response.json();
22
+ const id = body.config?.id;
23
+ expect(typeof id === "string" && id.length > 0).toBeTruthy();
24
+ return id;
25
+ }
26
+ async function deleteCurrenciesEntityIfExists(request, token, path, id) {
27
+ if (!token || !id) return;
28
+ try {
29
+ await apiRequest(request, "DELETE", `${path}?id=${encodeURIComponent(id)}`, { token });
30
+ } catch {
31
+ return;
32
+ }
33
+ }
34
+ export {
35
+ createCurrencyFixture,
36
+ createFetchConfigFixture,
37
+ deleteCurrenciesEntityIfExists
38
+ };
39
+ //# sourceMappingURL=currenciesFixtures.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../src/helpers/integration/currenciesFixtures.ts"],
4
+ "sourcesContent": ["import { expect, type APIRequestContext } from '@playwright/test';\nimport { apiRequest } from './api';\nimport { getTokenContext } from './generalFixtures';\n\nexport async function createCurrencyFixture(\n request: APIRequestContext,\n token: string,\n input: { code: string; name: string; symbol?: string },\n): Promise<string> {\n const { organizationId, tenantId } = getTokenContext(token);\n const response = await apiRequest(request, 'POST', '/api/currencies/currencies', {\n token,\n data: { organizationId, tenantId, code: input.code, name: input.name, symbol: input.symbol ?? null },\n });\n expect(response.ok(), `Failed to create currency fixture: ${response.status()}`).toBeTruthy();\n const body = (await response.json()) as { id?: string };\n expect(typeof body.id === 'string' && body.id.length > 0).toBeTruthy();\n return body.id as string;\n}\n\nexport async function createFetchConfigFixture(\n request: APIRequestContext,\n token: string,\n input: { provider: string; isEnabled: boolean },\n): Promise<string> {\n const response = await apiRequest(request, 'POST', '/api/currencies/fetch-configs', {\n token,\n data: input,\n });\n expect(response.ok(), `Failed to create fetch config fixture: ${response.status()}`).toBeTruthy();\n const body = (await response.json()) as { config?: { id?: string } };\n const id = body.config?.id;\n expect(typeof id === 'string' && id.length > 0).toBeTruthy();\n return id as string;\n}\n\nexport async function deleteCurrenciesEntityIfExists(\n request: APIRequestContext,\n token: string | null,\n path: string,\n id: string | null,\n): Promise<void> {\n if (!token || !id) return;\n try {\n await apiRequest(request, 'DELETE', `${path}?id=${encodeURIComponent(id)}`, { token });\n } catch {\n return;\n }\n}\n"],
5
+ "mappings": "AAAA,SAAS,cAAsC;AAC/C,SAAS,kBAAkB;AAC3B,SAAS,uBAAuB;AAEhC,eAAsB,sBACpB,SACA,OACA,OACiB;AACjB,QAAM,EAAE,gBAAgB,SAAS,IAAI,gBAAgB,KAAK;AAC1D,QAAM,WAAW,MAAM,WAAW,SAAS,QAAQ,8BAA8B;AAAA,IAC/E;AAAA,IACA,MAAM,EAAE,gBAAgB,UAAU,MAAM,MAAM,MAAM,MAAM,MAAM,MAAM,QAAQ,MAAM,UAAU,KAAK;AAAA,EACrG,CAAC;AACD,SAAO,SAAS,GAAG,GAAG,sCAAsC,SAAS,OAAO,CAAC,EAAE,EAAE,WAAW;AAC5F,QAAM,OAAQ,MAAM,SAAS,KAAK;AAClC,SAAO,OAAO,KAAK,OAAO,YAAY,KAAK,GAAG,SAAS,CAAC,EAAE,WAAW;AACrE,SAAO,KAAK;AACd;AAEA,eAAsB,yBACpB,SACA,OACA,OACiB;AACjB,QAAM,WAAW,MAAM,WAAW,SAAS,QAAQ,iCAAiC;AAAA,IAClF;AAAA,IACA,MAAM;AAAA,EACR,CAAC;AACD,SAAO,SAAS,GAAG,GAAG,0CAA0C,SAAS,OAAO,CAAC,EAAE,EAAE,WAAW;AAChG,QAAM,OAAQ,MAAM,SAAS,KAAK;AAClC,QAAM,KAAK,KAAK,QAAQ;AACxB,SAAO,OAAO,OAAO,YAAY,GAAG,SAAS,CAAC,EAAE,WAAW;AAC3D,SAAO;AACT;AAEA,eAAsB,+BACpB,SACA,OACA,MACA,IACe;AACf,MAAI,CAAC,SAAS,CAAC,GAAI;AACnB,MAAI;AACF,UAAM,WAAW,SAAS,UAAU,GAAG,IAAI,OAAO,mBAAmB,EAAE,CAAC,IAAI,EAAE,MAAM,CAAC;AAAA,EACvF,QAAQ;AACN;AAAA,EACF;AACF;",
6
+ "names": []
7
+ }
@@ -0,0 +1,16 @@
1
+ import { expect } from "@playwright/test";
2
+ import { apiRequest } from "./api.js";
3
+ async function createDictionaryFixture(request, token, input) {
4
+ const response = await apiRequest(request, "POST", "/api/dictionaries", {
5
+ token,
6
+ data: { key: input.key, name: input.name }
7
+ });
8
+ expect(response.ok(), `Failed to create dictionary fixture: ${response.status()}`).toBeTruthy();
9
+ const body = await response.json();
10
+ expect(typeof body.id === "string" && body.id.length > 0).toBeTruthy();
11
+ return body.id;
12
+ }
13
+ export {
14
+ createDictionaryFixture
15
+ };
16
+ //# sourceMappingURL=dictionariesFixtures.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../src/helpers/integration/dictionariesFixtures.ts"],
4
+ "sourcesContent": ["import { expect, type APIRequestContext } from '@playwright/test';\nimport { apiRequest } from './api';\n\nexport async function createDictionaryFixture(\n request: APIRequestContext,\n token: string,\n input: { key: string; name: string },\n): Promise<string> {\n const response = await apiRequest(request, 'POST', '/api/dictionaries', {\n token,\n data: { key: input.key, name: input.name },\n });\n expect(response.ok(), `Failed to create dictionary fixture: ${response.status()}`).toBeTruthy();\n const body = (await response.json()) as { id?: string };\n expect(typeof body.id === 'string' && body.id.length > 0).toBeTruthy();\n return body.id as string;\n}\n"],
5
+ "mappings": "AAAA,SAAS,cAAsC;AAC/C,SAAS,kBAAkB;AAE3B,eAAsB,wBACpB,SACA,OACA,OACiB;AACjB,QAAM,WAAW,MAAM,WAAW,SAAS,QAAQ,qBAAqB;AAAA,IACtE;AAAA,IACA,MAAM,EAAE,KAAK,MAAM,KAAK,MAAM,MAAM,KAAK;AAAA,EAC3C,CAAC;AACD,SAAO,SAAS,GAAG,GAAG,wCAAwC,SAAS,OAAO,CAAC,EAAE,EAAE,WAAW;AAC9F,QAAM,OAAQ,MAAM,SAAS,KAAK;AAClC,SAAO,OAAO,KAAK,OAAO,YAAY,KAAK,GAAG,SAAS,CAAC,EAAE,WAAW;AACrE,SAAO,KAAK;AACd;",
6
+ "names": []
7
+ }
@@ -0,0 +1,23 @@
1
+ import { expect } from "@playwright/test";
2
+ import { apiRequest } from "./api.js";
3
+ import { expectId, readJsonSafe } from "./generalFixtures.js";
4
+ async function createFeatureToggleFixture(request, token, data) {
5
+ const response = await apiRequest(request, "POST", "/api/feature_toggles/global", { token, data });
6
+ const body = await readJsonSafe(response);
7
+ expect(response.status(), "POST /api/feature_toggles/global should return 201").toBe(201);
8
+ return expectId(body?.id, "Feature toggle creation response should include id");
9
+ }
10
+ async function deleteFeatureToggleIfExists(request, token, toggleId) {
11
+ if (!token || !toggleId) return;
12
+ await apiRequest(
13
+ request,
14
+ "DELETE",
15
+ `/api/feature_toggles/global?id=${encodeURIComponent(toggleId)}`,
16
+ { token }
17
+ ).catch(() => void 0);
18
+ }
19
+ export {
20
+ createFeatureToggleFixture,
21
+ deleteFeatureToggleIfExists
22
+ };
23
+ //# sourceMappingURL=featureTogglesFixtures.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../src/helpers/integration/featureTogglesFixtures.ts"],
4
+ "sourcesContent": ["import { expect, type APIRequestContext } from '@playwright/test';\nimport { apiRequest } from './api';\nimport { expectId, readJsonSafe } from './generalFixtures';\n\nexport async function createFeatureToggleFixture(\n request: APIRequestContext,\n token: string,\n data: Record<string, unknown>,\n): Promise<string> {\n const response = await apiRequest(request, 'POST', '/api/feature_toggles/global', { token, data });\n const body = await readJsonSafe<{ id?: string }>(response);\n expect(response.status(), 'POST /api/feature_toggles/global should return 201').toBe(201);\n return expectId(body?.id, 'Feature toggle creation response should include id');\n}\n\nexport async function deleteFeatureToggleIfExists(\n request: APIRequestContext,\n token: string | null,\n toggleId: string | null,\n): Promise<void> {\n if (!token || !toggleId) return;\n await apiRequest(\n request,\n 'DELETE',\n `/api/feature_toggles/global?id=${encodeURIComponent(toggleId)}`,\n { token },\n ).catch(() => undefined);\n}\n"],
5
+ "mappings": "AAAA,SAAS,cAAsC;AAC/C,SAAS,kBAAkB;AAC3B,SAAS,UAAU,oBAAoB;AAEvC,eAAsB,2BACpB,SACA,OACA,MACiB;AACjB,QAAM,WAAW,MAAM,WAAW,SAAS,QAAQ,+BAA+B,EAAE,OAAO,KAAK,CAAC;AACjG,QAAM,OAAO,MAAM,aAA8B,QAAQ;AACzD,SAAO,SAAS,OAAO,GAAG,oDAAoD,EAAE,KAAK,GAAG;AACxF,SAAO,SAAS,MAAM,IAAI,oDAAoD;AAChF;AAEA,eAAsB,4BACpB,SACA,OACA,UACe;AACf,MAAI,CAAC,SAAS,CAAC,SAAU;AACzB,QAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA,kCAAkC,mBAAmB,QAAQ,CAAC;AAAA,IAC9D,EAAE,MAAM;AAAA,EACV,EAAE,MAAM,MAAM,MAAS;AACzB;",
6
+ "names": []
7
+ }
@@ -0,0 +1,56 @@
1
+ import { expect } from "@playwright/test";
2
+ import { apiRequest } from "./api.js";
3
+ function readTokenPayload(token) {
4
+ const parts = token.split(".");
5
+ return JSON.parse(Buffer.from(parts[1], "base64url").toString());
6
+ }
7
+ function getTokenContext(token) {
8
+ const payload = readTokenPayload(token);
9
+ return { organizationId: payload.orgId ?? "", tenantId: payload.tenantId ?? "" };
10
+ }
11
+ function getTokenScope(token) {
12
+ const payload = readTokenPayload(token);
13
+ return {
14
+ organizationId: payload.orgId ?? "",
15
+ tenantId: payload.tenantId ?? "",
16
+ userId: payload.sub ?? ""
17
+ };
18
+ }
19
+ async function readJsonSafe(response) {
20
+ const raw = await response.text();
21
+ if (!raw) return null;
22
+ try {
23
+ return JSON.parse(raw);
24
+ } catch {
25
+ return null;
26
+ }
27
+ }
28
+ function expectId(value, message) {
29
+ expect(typeof value === "string" && value.length > 0, message).toBe(true);
30
+ return value;
31
+ }
32
+ async function deleteEntityByPathIfExists(request, token, fullPath) {
33
+ if (!token || !fullPath) return;
34
+ try {
35
+ await apiRequest(request, "DELETE", fullPath, { token });
36
+ } catch {
37
+ return;
38
+ }
39
+ }
40
+ async function deleteGeneralEntityIfExists(request, token, path, id) {
41
+ if (!token || !id) return;
42
+ try {
43
+ await apiRequest(request, "DELETE", `${path}?id=${encodeURIComponent(id)}`, { token });
44
+ } catch {
45
+ return;
46
+ }
47
+ }
48
+ export {
49
+ deleteEntityByPathIfExists,
50
+ deleteGeneralEntityIfExists,
51
+ expectId,
52
+ getTokenContext,
53
+ getTokenScope,
54
+ readJsonSafe
55
+ };
56
+ //# sourceMappingURL=generalFixtures.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../src/helpers/integration/generalFixtures.ts"],
4
+ "sourcesContent": ["import { expect, type APIRequestContext, type APIResponse } from '@playwright/test';\nimport { apiRequest } from './api';\n\nfunction readTokenPayload(token: string): { orgId?: string; tenantId?: string; sub?: string } {\n const parts = token.split('.');\n return JSON.parse(Buffer.from(parts[1], 'base64url').toString()) as {\n orgId?: string;\n tenantId?: string;\n sub?: string;\n };\n}\n\nexport function getTokenContext(token: string): { organizationId: string; tenantId: string } {\n const payload = readTokenPayload(token);\n return { organizationId: payload.orgId ?? '', tenantId: payload.tenantId ?? '' };\n}\n\nexport function getTokenScope(token: string): {\n organizationId: string;\n tenantId: string;\n userId: string;\n} {\n const payload = readTokenPayload(token);\n return {\n organizationId: payload.orgId ?? '',\n tenantId: payload.tenantId ?? '',\n userId: payload.sub ?? '',\n };\n}\n\nexport async function readJsonSafe<T = unknown>(response: APIResponse): Promise<T | null> {\n const raw = await response.text();\n if (!raw) return null;\n try {\n return JSON.parse(raw) as T;\n } catch {\n return null;\n }\n}\n\nexport function expectId(value: unknown, message: string): string {\n expect(typeof value === 'string' && value.length > 0, message).toBe(true);\n return value as string;\n}\n\nexport async function deleteEntityByPathIfExists(\n request: APIRequestContext,\n token: string | null,\n fullPath: string | null,\n): Promise<void> {\n if (!token || !fullPath) return;\n try {\n await apiRequest(request, 'DELETE', fullPath, { token });\n } catch {\n return;\n }\n}\n\nexport async function deleteGeneralEntityIfExists(\n request: APIRequestContext,\n token: string | null,\n path: string,\n id: string | null,\n): Promise<void> {\n if (!token || !id) return;\n try {\n await apiRequest(request, 'DELETE', `${path}?id=${encodeURIComponent(id)}`, { token });\n } catch {\n return;\n }\n}\n"],
5
+ "mappings": "AAAA,SAAS,cAAwD;AACjE,SAAS,kBAAkB;AAE3B,SAAS,iBAAiB,OAAoE;AAC5F,QAAM,QAAQ,MAAM,MAAM,GAAG;AAC7B,SAAO,KAAK,MAAM,OAAO,KAAK,MAAM,CAAC,GAAG,WAAW,EAAE,SAAS,CAAC;AAKjE;AAEO,SAAS,gBAAgB,OAA6D;AAC3F,QAAM,UAAU,iBAAiB,KAAK;AACtC,SAAO,EAAE,gBAAgB,QAAQ,SAAS,IAAI,UAAU,QAAQ,YAAY,GAAG;AACjF;AAEO,SAAS,cAAc,OAI5B;AACA,QAAM,UAAU,iBAAiB,KAAK;AACtC,SAAO;AAAA,IACL,gBAAgB,QAAQ,SAAS;AAAA,IACjC,UAAU,QAAQ,YAAY;AAAA,IAC9B,QAAQ,QAAQ,OAAO;AAAA,EACzB;AACF;AAEA,eAAsB,aAA0B,UAA0C;AACxF,QAAM,MAAM,MAAM,SAAS,KAAK;AAChC,MAAI,CAAC,IAAK,QAAO;AACjB,MAAI;AACF,WAAO,KAAK,MAAM,GAAG;AAAA,EACvB,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEO,SAAS,SAAS,OAAgB,SAAyB;AAChE,SAAO,OAAO,UAAU,YAAY,MAAM,SAAS,GAAG,OAAO,EAAE,KAAK,IAAI;AACxE,SAAO;AACT;AAEA,eAAsB,2BACpB,SACA,OACA,UACe;AACf,MAAI,CAAC,SAAS,CAAC,SAAU;AACzB,MAAI;AACF,UAAM,WAAW,SAAS,UAAU,UAAU,EAAE,MAAM,CAAC;AAAA,EACzD,QAAQ;AACN;AAAA,EACF;AACF;AAEA,eAAsB,4BACpB,SACA,OACA,MACA,IACe;AACf,MAAI,CAAC,SAAS,CAAC,GAAI;AACnB,MAAI;AACF,UAAM,WAAW,SAAS,UAAU,GAAG,IAAI,OAAO,mBAAmB,EAAE,CAAC,IAAI,EAAE,MAAM,CAAC;AAAA,EACvF,QAAQ;AACN;AAAA,EACF;AACF;",
6
+ "names": []
7
+ }
@@ -0,0 +1,67 @@
1
+ import { apiRequest } from "./api.js";
2
+ import { readJsonSafe } from "./crmFixtures.js";
3
+ async function submitTextExtraction(request, token, input) {
4
+ const text = input?.text ?? "Test email from John Doe <john@example.com> requesting 10 widgets at $5 each.";
5
+ const title = input?.title ?? `QA Fixture ${Date.now()}`;
6
+ const response = await apiRequest(request, "POST", "/api/inbox_ops/extract", {
7
+ token,
8
+ data: { text, title, metadata: input?.metadata }
9
+ });
10
+ const body = await readJsonSafe(response);
11
+ return {
12
+ ok: response.ok(),
13
+ emailId: body?.emailId ?? void 0,
14
+ error: body?.error ?? void 0,
15
+ status: response.status()
16
+ };
17
+ }
18
+ async function waitForEmailProcessed(request, token, emailId, timeoutMs = 3e4) {
19
+ const pollInterval = 1e3;
20
+ const deadline = Date.now() + timeoutMs;
21
+ while (Date.now() < deadline) {
22
+ const response = await apiRequest(request, "GET", `/api/inbox_ops/emails/${emailId}`, { token });
23
+ if (!response.ok()) return null;
24
+ const body = await readJsonSafe(response);
25
+ const status = body?.email?.status;
26
+ if (status === "processed" || status === "needs_review" || status === "failed") {
27
+ const proposalsResponse = await apiRequest(request, "GET", "/api/inbox_ops/proposals?pageSize=5", { token });
28
+ const proposalsBody = await readJsonSafe(proposalsResponse);
29
+ const proposal = proposalsBody?.items?.find((p) => p.inboxEmailId === emailId);
30
+ return { status, proposalId: proposal?.id };
31
+ }
32
+ await new Promise((resolve) => setTimeout(resolve, pollInterval));
33
+ }
34
+ return null;
35
+ }
36
+ async function deleteInboxEmail(request, token, emailId) {
37
+ await apiRequest(request, "DELETE", `/api/inbox_ops/emails/${emailId}`, { token }).catch(() => {
38
+ });
39
+ }
40
+ async function listInboxEmails(request, token, params) {
41
+ const searchParams = new URLSearchParams();
42
+ if (params?.status) searchParams.set("status", params.status);
43
+ if (params?.page) searchParams.set("page", String(params.page));
44
+ if (params?.pageSize) searchParams.set("pageSize", String(params.pageSize));
45
+ const path = `/api/inbox_ops/emails${searchParams.toString() ? `?${searchParams}` : ""}`;
46
+ const response = await apiRequest(request, "GET", path, { token });
47
+ const body = await readJsonSafe(response);
48
+ return { items: body?.items ?? [], total: body?.total ?? 0 };
49
+ }
50
+ async function listInboxProposals(request, token, params) {
51
+ const searchParams = new URLSearchParams();
52
+ if (params?.status) searchParams.set("status", params.status);
53
+ if (params?.page) searchParams.set("page", String(params.page));
54
+ if (params?.pageSize) searchParams.set("pageSize", String(params.pageSize));
55
+ const path = `/api/inbox_ops/proposals${searchParams.toString() ? `?${searchParams}` : ""}`;
56
+ const response = await apiRequest(request, "GET", path, { token });
57
+ const body = await readJsonSafe(response);
58
+ return { items: body?.items ?? [], total: body?.total ?? 0 };
59
+ }
60
+ export {
61
+ deleteInboxEmail,
62
+ listInboxEmails,
63
+ listInboxProposals,
64
+ submitTextExtraction,
65
+ waitForEmailProcessed
66
+ };
67
+ //# sourceMappingURL=inboxFixtures.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../src/helpers/integration/inboxFixtures.ts"],
4
+ "sourcesContent": ["import type { APIRequestContext } from '@playwright/test';\nimport { apiRequest } from './api';\nimport { readJsonSafe } from './crmFixtures';\n\nexport async function submitTextExtraction(\n request: APIRequestContext,\n token: string,\n input?: { text?: string; title?: string; metadata?: Record<string, unknown> },\n): Promise<{ ok: boolean; emailId?: string; error?: string; status: number }> {\n const text = input?.text ?? 'Test email from John Doe <john@example.com> requesting 10 widgets at $5 each.'\n const title = input?.title ?? `QA Fixture ${Date.now()}`\n\n const response = await apiRequest(request, 'POST', '/api/inbox_ops/extract', {\n token,\n data: { text, title, metadata: input?.metadata },\n });\n\n const body = await readJsonSafe<{ ok?: boolean; emailId?: string; error?: string }>(response);\n return {\n ok: response.ok(),\n emailId: body?.emailId ?? undefined,\n error: body?.error ?? undefined,\n status: response.status(),\n };\n}\n\nexport async function waitForEmailProcessed(\n request: APIRequestContext,\n token: string,\n emailId: string,\n timeoutMs = 30000,\n): Promise<{ status: string; proposalId?: string } | null> {\n const pollInterval = 1000\n const deadline = Date.now() + timeoutMs\n\n while (Date.now() < deadline) {\n const response = await apiRequest(request, 'GET', `/api/inbox_ops/emails/${emailId}`, { token });\n if (!response.ok()) return null\n\n const body = await readJsonSafe<{ email?: { status?: string; id?: string } }>(response);\n const status = body?.email?.status\n\n if (status === 'processed' || status === 'needs_review' || status === 'failed') {\n const proposalsResponse = await apiRequest(request, 'GET', '/api/inbox_ops/proposals?pageSize=5', { token });\n const proposalsBody = await readJsonSafe<{ items?: Array<{ id: string; inboxEmailId?: string }> }>(proposalsResponse);\n const proposal = proposalsBody?.items?.find((p) => p.inboxEmailId === emailId);\n return { status, proposalId: proposal?.id };\n }\n\n await new Promise((resolve) => setTimeout(resolve, pollInterval))\n }\n\n return null\n}\n\nexport async function deleteInboxEmail(\n request: APIRequestContext,\n token: string,\n emailId: string,\n): Promise<void> {\n await apiRequest(request, 'DELETE', `/api/inbox_ops/emails/${emailId}`, { token }).catch(() => {})\n}\n\nexport async function listInboxEmails(\n request: APIRequestContext,\n token: string,\n params?: { status?: string; page?: number; pageSize?: number },\n): Promise<{ items: Array<Record<string, unknown>>; total: number }> {\n const searchParams = new URLSearchParams();\n if (params?.status) searchParams.set('status', params.status);\n if (params?.page) searchParams.set('page', String(params.page));\n if (params?.pageSize) searchParams.set('pageSize', String(params.pageSize));\n\n const path = `/api/inbox_ops/emails${searchParams.toString() ? `?${searchParams}` : ''}`;\n const response = await apiRequest(request, 'GET', path, { token });\n const body = await readJsonSafe<{ items?: Array<Record<string, unknown>>; total?: number }>(response);\n return { items: body?.items ?? [], total: body?.total ?? 0 };\n}\n\nexport async function listInboxProposals(\n request: APIRequestContext,\n token: string,\n params?: { status?: string; page?: number; pageSize?: number },\n): Promise<{ items: Array<Record<string, unknown>>; total: number }> {\n const searchParams = new URLSearchParams();\n if (params?.status) searchParams.set('status', params.status);\n if (params?.page) searchParams.set('page', String(params.page));\n if (params?.pageSize) searchParams.set('pageSize', String(params.pageSize));\n\n const path = `/api/inbox_ops/proposals${searchParams.toString() ? `?${searchParams}` : ''}`;\n const response = await apiRequest(request, 'GET', path, { token });\n const body = await readJsonSafe<{ items?: Array<Record<string, unknown>>; total?: number }>(response);\n return { items: body?.items ?? [], total: body?.total ?? 0 };\n}\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }
@@ -0,0 +1,48 @@
1
+ import { expect } from "@playwright/test";
2
+ import { apiRequest } from "./api.js";
3
+ import { expectId, readJsonSafe } from "./generalFixtures.js";
4
+ async function createNotificationFixture(request, token, data) {
5
+ const response = await apiRequest(request, "POST", "/api/notifications", { token, data });
6
+ const body = await readJsonSafe(response);
7
+ expect(response.status(), "POST /api/notifications should return 201").toBe(201);
8
+ return expectId(body?.id, "Notification creation response should include id");
9
+ }
10
+ async function listNotifications(request, token, query) {
11
+ const params = new URLSearchParams();
12
+ for (const [key, value] of Object.entries(query ?? {})) {
13
+ if (value === void 0) continue;
14
+ params.set(key, String(value));
15
+ }
16
+ const path = `/api/notifications${params.toString() ? `?${params.toString()}` : ""}`;
17
+ const response = await apiRequest(request, "GET", path, { token });
18
+ const body = await readJsonSafe(response);
19
+ expect(response.ok(), `GET ${path} should succeed`).toBeTruthy();
20
+ return {
21
+ items: body?.items ?? [],
22
+ total: body?.total ?? 0
23
+ };
24
+ }
25
+ async function dismissNotificationIfExists(request, token, notificationId) {
26
+ if (!token || !notificationId) return;
27
+ await apiRequest(
28
+ request,
29
+ "PUT",
30
+ `/api/notifications/${encodeURIComponent(notificationId)}/dismiss`,
31
+ { token }
32
+ ).catch(() => void 0);
33
+ }
34
+ async function dismissNotificationsByType(request, token, type) {
35
+ if (!token || !type) return;
36
+ const notifications = await listNotifications(request, token, { type, pageSize: 100 }).catch(() => null);
37
+ if (!notifications) return;
38
+ await Promise.all(
39
+ notifications.items.map((item) => typeof item.id === "string" ? item.id : null).filter((id) => Boolean(id)).map((id) => dismissNotificationIfExists(request, token, id))
40
+ );
41
+ }
42
+ export {
43
+ createNotificationFixture,
44
+ dismissNotificationIfExists,
45
+ dismissNotificationsByType,
46
+ listNotifications
47
+ };
48
+ //# sourceMappingURL=notificationsFixtures.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../src/helpers/integration/notificationsFixtures.ts"],
4
+ "sourcesContent": ["import { expect, type APIRequestContext } from '@playwright/test';\nimport { apiRequest } from './api';\nimport { expectId, readJsonSafe } from './generalFixtures';\n\nexport async function createNotificationFixture(\n request: APIRequestContext,\n token: string,\n data: Record<string, unknown>,\n): Promise<string> {\n const response = await apiRequest(request, 'POST', '/api/notifications', { token, data });\n const body = await readJsonSafe<{ id?: string }>(response);\n expect(response.status(), 'POST /api/notifications should return 201').toBe(201);\n return expectId(body?.id, 'Notification creation response should include id');\n}\n\nexport async function listNotifications(\n request: APIRequestContext,\n token: string,\n query?: Record<string, string | number | undefined>,\n): Promise<{\n items: Array<Record<string, unknown>>;\n total: number;\n}> {\n const params = new URLSearchParams();\n for (const [key, value] of Object.entries(query ?? {})) {\n if (value === undefined) continue;\n params.set(key, String(value));\n }\n const path = `/api/notifications${params.toString() ? `?${params.toString()}` : ''}`;\n const response = await apiRequest(request, 'GET', path, { token });\n const body = await readJsonSafe<{ items?: Array<Record<string, unknown>>; total?: number }>(response);\n expect(response.ok(), `GET ${path} should succeed`).toBeTruthy();\n return {\n items: body?.items ?? [],\n total: body?.total ?? 0,\n };\n}\n\nexport async function dismissNotificationIfExists(\n request: APIRequestContext,\n token: string | null,\n notificationId: string | null,\n): Promise<void> {\n if (!token || !notificationId) return;\n await apiRequest(\n request,\n 'PUT',\n `/api/notifications/${encodeURIComponent(notificationId)}/dismiss`,\n { token },\n ).catch(() => undefined);\n}\n\nexport async function dismissNotificationsByType(\n request: APIRequestContext,\n token: string | null,\n type: string | null,\n): Promise<void> {\n if (!token || !type) return;\n const notifications = await listNotifications(request, token, { type, pageSize: 100 }).catch(() => null);\n if (!notifications) return;\n await Promise.all(\n notifications.items\n .map((item) => (typeof item.id === 'string' ? item.id : null))\n .filter((id): id is string => Boolean(id))\n .map((id) => dismissNotificationIfExists(request, token, id)),\n );\n}\n"],
5
+ "mappings": "AAAA,SAAS,cAAsC;AAC/C,SAAS,kBAAkB;AAC3B,SAAS,UAAU,oBAAoB;AAEvC,eAAsB,0BACpB,SACA,OACA,MACiB;AACjB,QAAM,WAAW,MAAM,WAAW,SAAS,QAAQ,sBAAsB,EAAE,OAAO,KAAK,CAAC;AACxF,QAAM,OAAO,MAAM,aAA8B,QAAQ;AACzD,SAAO,SAAS,OAAO,GAAG,2CAA2C,EAAE,KAAK,GAAG;AAC/E,SAAO,SAAS,MAAM,IAAI,kDAAkD;AAC9E;AAEA,eAAsB,kBACpB,SACA,OACA,OAIC;AACD,QAAM,SAAS,IAAI,gBAAgB;AACnC,aAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,SAAS,CAAC,CAAC,GAAG;AACtD,QAAI,UAAU,OAAW;AACzB,WAAO,IAAI,KAAK,OAAO,KAAK,CAAC;AAAA,EAC/B;AACA,QAAM,OAAO,qBAAqB,OAAO,SAAS,IAAI,IAAI,OAAO,SAAS,CAAC,KAAK,EAAE;AAClF,QAAM,WAAW,MAAM,WAAW,SAAS,OAAO,MAAM,EAAE,MAAM,CAAC;AACjE,QAAM,OAAO,MAAM,aAAyE,QAAQ;AACpG,SAAO,SAAS,GAAG,GAAG,OAAO,IAAI,iBAAiB,EAAE,WAAW;AAC/D,SAAO;AAAA,IACL,OAAO,MAAM,SAAS,CAAC;AAAA,IACvB,OAAO,MAAM,SAAS;AAAA,EACxB;AACF;AAEA,eAAsB,4BACpB,SACA,OACA,gBACe;AACf,MAAI,CAAC,SAAS,CAAC,eAAgB;AAC/B,QAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA,sBAAsB,mBAAmB,cAAc,CAAC;AAAA,IACxD,EAAE,MAAM;AAAA,EACV,EAAE,MAAM,MAAM,MAAS;AACzB;AAEA,eAAsB,2BACpB,SACA,OACA,MACe;AACf,MAAI,CAAC,SAAS,CAAC,KAAM;AACrB,QAAM,gBAAgB,MAAM,kBAAkB,SAAS,OAAO,EAAE,MAAM,UAAU,IAAI,CAAC,EAAE,MAAM,MAAM,IAAI;AACvG,MAAI,CAAC,cAAe;AACpB,QAAM,QAAQ;AAAA,IACZ,cAAc,MACX,IAAI,CAAC,SAAU,OAAO,KAAK,OAAO,WAAW,KAAK,KAAK,IAAK,EAC5D,OAAO,CAAC,OAAqB,QAAQ,EAAE,CAAC,EACxC,IAAI,CAAC,OAAO,4BAA4B,SAAS,OAAO,EAAE,CAAC;AAAA,EAChE;AACF;",
6
+ "names": []
7
+ }
@@ -0,0 +1,63 @@
1
+ import { expect } from "@playwright/test";
2
+ import { apiRequest } from "./api.js";
3
+ function readId(payload, keys) {
4
+ if (!payload || typeof payload !== "object") return null;
5
+ const map = payload;
6
+ for (const key of keys) {
7
+ const value = map[key];
8
+ if (typeof value === "string" && value.length > 0) return value;
9
+ }
10
+ for (const value of Object.values(map)) {
11
+ if (value && typeof value === "object" && !Array.isArray(value)) {
12
+ const nested = readId(value, keys);
13
+ if (nested) return nested;
14
+ }
15
+ }
16
+ return null;
17
+ }
18
+ async function createEntity(request, token, path, data, idKeys) {
19
+ const response = await apiRequest(request, "POST", path, { token, data });
20
+ const body = await response.json();
21
+ expect(response.ok(), `Failed POST ${path}: ${response.status()}`).toBeTruthy();
22
+ const id = readId(body, idKeys);
23
+ expect(id, `No id in POST ${path} response`).toBeTruthy();
24
+ return id;
25
+ }
26
+ async function createSalesQuoteFixture(request, token, currencyCode = "USD") {
27
+ return createEntity(request, token, "/api/sales/quotes", { currencyCode }, ["id", "quoteId"]);
28
+ }
29
+ async function createSalesOrderFixture(request, token, currencyCode = "USD") {
30
+ return createEntity(request, token, "/api/sales/orders", { currencyCode }, ["id", "orderId"]);
31
+ }
32
+ async function createOrderLineFixture(request, token, orderId, data) {
33
+ return createEntity(
34
+ request,
35
+ token,
36
+ "/api/sales/order-lines",
37
+ {
38
+ orderId,
39
+ currencyCode: "USD",
40
+ quantity: 1,
41
+ name: `QA line ${Date.now()}`,
42
+ unitPriceNet: 10,
43
+ unitPriceGross: 12,
44
+ ...data ?? {}
45
+ },
46
+ ["id", "lineId"]
47
+ );
48
+ }
49
+ async function deleteSalesEntityIfExists(request, token, path, id) {
50
+ if (!token || !id) return;
51
+ try {
52
+ await apiRequest(request, "DELETE", `${path}?id=${encodeURIComponent(id)}`, { token });
53
+ } catch {
54
+ return;
55
+ }
56
+ }
57
+ export {
58
+ createOrderLineFixture,
59
+ createSalesOrderFixture,
60
+ createSalesQuoteFixture,
61
+ deleteSalesEntityIfExists
62
+ };
63
+ //# sourceMappingURL=salesFixtures.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../src/helpers/integration/salesFixtures.ts"],
4
+ "sourcesContent": ["import { expect, type APIRequestContext } from '@playwright/test';\nimport { apiRequest } from './api';\n\ntype JsonMap = Record<string, unknown>;\n\nfunction readId(payload: unknown, keys: string[]): string | null {\n if (!payload || typeof payload !== 'object') return null;\n const map = payload as JsonMap;\n for (const key of keys) {\n const value = map[key];\n if (typeof value === 'string' && value.length > 0) return value;\n }\n for (const value of Object.values(map)) {\n if (value && typeof value === 'object' && !Array.isArray(value)) {\n const nested = readId(value, keys);\n if (nested) return nested;\n }\n }\n return null;\n}\n\nasync function createEntity(\n request: APIRequestContext,\n token: string,\n path: string,\n data: Record<string, unknown>,\n idKeys: string[],\n): Promise<string> {\n const response = await apiRequest(request, 'POST', path, { token, data });\n const body = (await response.json()) as unknown;\n expect(response.ok(), `Failed POST ${path}: ${response.status()}`).toBeTruthy();\n const id = readId(body, idKeys);\n expect(id, `No id in POST ${path} response`).toBeTruthy();\n return id as string;\n}\n\nexport async function createSalesQuoteFixture(\n request: APIRequestContext,\n token: string,\n currencyCode = 'USD',\n): Promise<string> {\n return createEntity(request, token, '/api/sales/quotes', { currencyCode }, ['id', 'quoteId']);\n}\n\nexport async function createSalesOrderFixture(\n request: APIRequestContext,\n token: string,\n currencyCode = 'USD',\n): Promise<string> {\n return createEntity(request, token, '/api/sales/orders', { currencyCode }, ['id', 'orderId']);\n}\n\nexport async function createOrderLineFixture(\n request: APIRequestContext,\n token: string,\n orderId: string,\n data?: Record<string, unknown>,\n): Promise<string> {\n return createEntity(\n request,\n token,\n '/api/sales/order-lines',\n {\n orderId,\n currencyCode: 'USD',\n quantity: 1,\n name: `QA line ${Date.now()}`,\n unitPriceNet: 10,\n unitPriceGross: 12,\n ...(data ?? {}),\n },\n ['id', 'lineId'],\n );\n}\n\nexport async function deleteSalesEntityIfExists(\n request: APIRequestContext,\n token: string | null,\n path: string,\n id: string | null,\n): Promise<void> {\n if (!token || !id) return;\n try {\n await apiRequest(request, 'DELETE', `${path}?id=${encodeURIComponent(id)}`, { token });\n } catch {\n return;\n }\n}\n\n"],
5
+ "mappings": "AAAA,SAAS,cAAsC;AAC/C,SAAS,kBAAkB;AAI3B,SAAS,OAAO,SAAkB,MAA+B;AAC/D,MAAI,CAAC,WAAW,OAAO,YAAY,SAAU,QAAO;AACpD,QAAM,MAAM;AACZ,aAAW,OAAO,MAAM;AACtB,UAAM,QAAQ,IAAI,GAAG;AACrB,QAAI,OAAO,UAAU,YAAY,MAAM,SAAS,EAAG,QAAO;AAAA,EAC5D;AACA,aAAW,SAAS,OAAO,OAAO,GAAG,GAAG;AACtC,QAAI,SAAS,OAAO,UAAU,YAAY,CAAC,MAAM,QAAQ,KAAK,GAAG;AAC/D,YAAM,SAAS,OAAO,OAAO,IAAI;AACjC,UAAI,OAAQ,QAAO;AAAA,IACrB;AAAA,EACF;AACA,SAAO;AACT;AAEA,eAAe,aACb,SACA,OACA,MACA,MACA,QACiB;AACjB,QAAM,WAAW,MAAM,WAAW,SAAS,QAAQ,MAAM,EAAE,OAAO,KAAK,CAAC;AACxE,QAAM,OAAQ,MAAM,SAAS,KAAK;AAClC,SAAO,SAAS,GAAG,GAAG,eAAe,IAAI,KAAK,SAAS,OAAO,CAAC,EAAE,EAAE,WAAW;AAC9E,QAAM,KAAK,OAAO,MAAM,MAAM;AAC9B,SAAO,IAAI,iBAAiB,IAAI,WAAW,EAAE,WAAW;AACxD,SAAO;AACT;AAEA,eAAsB,wBACpB,SACA,OACA,eAAe,OACE;AACjB,SAAO,aAAa,SAAS,OAAO,qBAAqB,EAAE,aAAa,GAAG,CAAC,MAAM,SAAS,CAAC;AAC9F;AAEA,eAAsB,wBACpB,SACA,OACA,eAAe,OACE;AACjB,SAAO,aAAa,SAAS,OAAO,qBAAqB,EAAE,aAAa,GAAG,CAAC,MAAM,SAAS,CAAC;AAC9F;AAEA,eAAsB,uBACpB,SACA,OACA,SACA,MACiB;AACjB,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,MACE;AAAA,MACA,cAAc;AAAA,MACd,UAAU;AAAA,MACV,MAAM,WAAW,KAAK,IAAI,CAAC;AAAA,MAC3B,cAAc;AAAA,MACd,gBAAgB;AAAA,MAChB,GAAI,QAAQ,CAAC;AAAA,IACf;AAAA,IACA,CAAC,MAAM,QAAQ;AAAA,EACjB;AACF;AAEA,eAAsB,0BACpB,SACA,OACA,MACA,IACe;AACf,MAAI,CAAC,SAAS,CAAC,GAAI;AACnB,MAAI;AACF,UAAM,WAAW,SAAS,UAAU,GAAG,IAAI,OAAO,mBAAmB,EAAE,CAAC,IAAI,EAAE,MAAM,CAAC;AAAA,EACvF,QAAQ;AACN;AAAA,EACF;AACF;",
6
+ "names": []
7
+ }