@greatapps/common 1.1.713 → 1.1.714
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/dist/testing/constants.mjs +21 -0
- package/dist/testing/constants.mjs.map +1 -0
- package/dist/testing/factories/account.factory.mjs +38 -0
- package/dist/testing/factories/account.factory.mjs.map +1 -0
- package/dist/testing/factories/create-mock.mjs +16 -0
- package/dist/testing/factories/create-mock.mjs.map +1 -0
- package/dist/testing/factories/index.mjs +21 -0
- package/dist/testing/factories/index.mjs.map +1 -0
- package/dist/testing/factories/jwt.mjs +33 -0
- package/dist/testing/factories/jwt.mjs.map +1 -0
- package/dist/testing/factories/plan.factory.mjs +23 -0
- package/dist/testing/factories/plan.factory.mjs.map +1 -0
- package/dist/testing/factories/subscription.factory.mjs +52 -0
- package/dist/testing/factories/subscription.factory.mjs.map +1 -0
- package/dist/testing/factories/user.factory.mjs +36 -0
- package/dist/testing/factories/user.factory.mjs.map +1 -0
- package/dist/testing/factories/whitelabel.factory.mjs +66 -0
- package/dist/testing/factories/whitelabel.factory.mjs.map +1 -0
- package/dist/testing/index.mjs +10 -0
- package/dist/testing/index.mjs.map +1 -0
- package/dist/testing/msw/envelope.mjs +20 -0
- package/dist/testing/msw/envelope.mjs.map +1 -0
- package/dist/testing/msw/index.mjs +10 -0
- package/dist/testing/msw/index.mjs.map +1 -0
- package/dist/testing/msw/session.handlers.mjs +23 -0
- package/dist/testing/msw/session.handlers.mjs.map +1 -0
- package/dist/testing/react/index.mjs +8 -0
- package/dist/testing/react/index.mjs.map +1 -0
- package/dist/testing/react/providers.mjs +42 -0
- package/dist/testing/react/providers.mjs.map +1 -0
- package/dist/testing/react/test-query-client.mjs +13 -0
- package/dist/testing/react/test-query-client.mjs.map +1 -0
- package/dist/testing.mjs +2 -0
- package/dist/testing.mjs.map +1 -0
- package/package.json +21 -1
- package/src/testing/constants.ts +28 -0
- package/src/testing/factories/account.factory.ts +37 -0
- package/src/testing/factories/create-mock.ts +23 -0
- package/src/testing/factories/index.ts +7 -0
- package/src/testing/factories/jwt.ts +44 -0
- package/src/testing/factories/plan.factory.ts +21 -0
- package/src/testing/factories/subscription.factory.ts +52 -0
- package/src/testing/factories/user.factory.ts +35 -0
- package/src/testing/factories/whitelabel.factory.ts +67 -0
- package/src/testing/index.ts +11 -0
- package/src/testing/msw/envelope.ts +23 -0
- package/src/testing/msw/index.ts +2 -0
- package/src/testing/msw/session.handlers.ts +38 -0
- package/src/testing/react/index.ts +2 -0
- package/src/testing/react/providers.tsx +65 -0
- package/src/testing/react/test-query-client.ts +14 -0
- package/src/testing.ts +1 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
const TEST_IDS = {
|
|
2
|
+
wl: 1,
|
|
3
|
+
account: 123,
|
|
4
|
+
user: 456,
|
|
5
|
+
page: 789
|
|
6
|
+
};
|
|
7
|
+
const TEST_API = {
|
|
8
|
+
gapps: "https://gapps.test",
|
|
9
|
+
gpages: "https://gpages.test",
|
|
10
|
+
masterToken: "test-master-token",
|
|
11
|
+
domain: "app.test"
|
|
12
|
+
};
|
|
13
|
+
const TEST_API_VERSION = "v1";
|
|
14
|
+
const TEST_API_LOCALE = "pt-br";
|
|
15
|
+
export {
|
|
16
|
+
TEST_API,
|
|
17
|
+
TEST_API_LOCALE,
|
|
18
|
+
TEST_API_VERSION,
|
|
19
|
+
TEST_IDS
|
|
20
|
+
};
|
|
21
|
+
//# sourceMappingURL=constants.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/testing/constants.ts"],"sourcesContent":["// Fixed identity and endpoints used across the test infra. Single source of truth: the same\n// object feeds DUMMY_AUTH_TOKEN (via createTestJwt), the factories and the request handlers, and\n// consumer apps must mirror it in their test env (GAPPS_R3_API_URL etc.) so the URL the ApiClient\n// builds matches the one the handlers expect.\nexport const TEST_IDS = {\n wl: 1,\n account: 123,\n user: 456,\n page: 789,\n} as const;\n\n// Bases the apps MUST export as test env:\n// GAPPS_R3_API_URL = TEST_API.gapps\n// GPAGES_R3_API_URL = TEST_API.gpages\n// WHITELABEL_TOKEN_MASTER = TEST_API.masterToken\n// WHITELABEL_DOMAIN = TEST_API.domain\n// `.test` domains never resolve on the real network, so a leaked unhandled request fails loudly\n// instead of hitting a real backend.\nexport const TEST_API = {\n gapps: 'https://gapps.test',\n gpages: 'https://gpages.test',\n masterToken: 'test-master-token',\n domain: 'app.test',\n} as const;\n\n// Fixed locale and version the ApiClient uses to build the URL (`/v1/pt-br/{wl}`).\nexport const TEST_API_VERSION = 'v1';\nexport const TEST_API_LOCALE = 'pt-br';\n"],"mappings":"AAIO,MAAM,WAAW;AAAA,EACtB,IAAI;AAAA,EACJ,SAAS;AAAA,EACT,MAAM;AAAA,EACN,MAAM;AACR;AASO,MAAM,WAAW;AAAA,EACtB,OAAO;AAAA,EACP,QAAQ;AAAA,EACR,aAAa;AAAA,EACb,QAAQ;AACV;AAGO,MAAM,mBAAmB;AACzB,MAAM,kBAAkB;","names":[]}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { faker } from "@faker-js/faker";
|
|
2
|
+
import { TEST_IDS } from "../constants";
|
|
3
|
+
import { createMock } from "./create-mock";
|
|
4
|
+
const createAccountMock = createMock((overrides) => ({
|
|
5
|
+
id: overrides?.id ?? TEST_IDS.account,
|
|
6
|
+
id_wl: overrides?.id_wl ?? TEST_IDS.wl,
|
|
7
|
+
id_affiliate: overrides?.id_affiliate ?? 0,
|
|
8
|
+
id_api: overrides?.id_api ?? 1,
|
|
9
|
+
name: overrides?.name || faker.company.name(),
|
|
10
|
+
language: overrides?.language ?? "pt-br",
|
|
11
|
+
timezone: overrides?.timezone ?? "America/Sao_Paulo",
|
|
12
|
+
currency: overrides?.currency ?? "brl",
|
|
13
|
+
verified: overrides?.verified ?? true,
|
|
14
|
+
bussiness_type: overrides?.bussiness_type ?? 1,
|
|
15
|
+
gateway: overrides?.gateway ?? "stripe",
|
|
16
|
+
gateway_customer_id: overrides?.gateway_customer_id ?? null,
|
|
17
|
+
origin: overrides?.origin ?? null,
|
|
18
|
+
zipcode: overrides?.zipcode ?? null,
|
|
19
|
+
address: overrides?.address ?? null,
|
|
20
|
+
address_number: overrides?.address_number ?? null,
|
|
21
|
+
address_complement: overrides?.address_complement ?? null,
|
|
22
|
+
neighborhood: overrides?.neighborhood ?? null,
|
|
23
|
+
city: overrides?.city ?? null,
|
|
24
|
+
state: overrides?.state ?? null,
|
|
25
|
+
country: overrides?.country ?? "BR",
|
|
26
|
+
financial_document: overrides?.financial_document ?? null,
|
|
27
|
+
financial_name: overrides?.financial_name ?? null,
|
|
28
|
+
financial_email: overrides?.financial_email ?? null,
|
|
29
|
+
financial_document_type: overrides?.financial_document_type ?? 1,
|
|
30
|
+
deleted: overrides?.deleted ?? 0,
|
|
31
|
+
datetime_add: overrides?.datetime_add || "2025-01-01 00:00:00",
|
|
32
|
+
datetime_alt: overrides?.datetime_alt || "2025-01-01 00:00:00",
|
|
33
|
+
datetime_del: overrides?.datetime_del ?? null
|
|
34
|
+
}));
|
|
35
|
+
export {
|
|
36
|
+
createAccountMock
|
|
37
|
+
};
|
|
38
|
+
//# sourceMappingURL=account.factory.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/testing/factories/account.factory.ts"],"sourcesContent":["import { faker } from '@faker-js/faker';\nimport { Account } from '../../modules/accounts/types';\nimport { TEST_IDS } from '../constants';\nimport { createMock } from './create-mock';\n\n// Identity fields (id/id_wl) are fixed to TEST_IDS; cosmetic fields use faker.\nexport const createAccountMock = createMock<Account, Partial<Account>>((overrides) => ({\n id: overrides?.id ?? TEST_IDS.account,\n id_wl: overrides?.id_wl ?? TEST_IDS.wl,\n id_affiliate: overrides?.id_affiliate ?? 0,\n id_api: overrides?.id_api ?? 1,\n name: overrides?.name || faker.company.name(),\n language: overrides?.language ?? 'pt-br',\n timezone: overrides?.timezone ?? 'America/Sao_Paulo',\n currency: overrides?.currency ?? 'brl',\n verified: overrides?.verified ?? true,\n bussiness_type: overrides?.bussiness_type ?? 1,\n gateway: overrides?.gateway ?? 'stripe',\n gateway_customer_id: overrides?.gateway_customer_id ?? null,\n origin: overrides?.origin ?? null,\n zipcode: overrides?.zipcode ?? null,\n address: overrides?.address ?? null,\n address_number: overrides?.address_number ?? null,\n address_complement: overrides?.address_complement ?? null,\n neighborhood: overrides?.neighborhood ?? null,\n city: overrides?.city ?? null,\n state: overrides?.state ?? null,\n country: overrides?.country ?? 'BR',\n financial_document: overrides?.financial_document ?? null,\n financial_name: overrides?.financial_name ?? null,\n financial_email: overrides?.financial_email ?? null,\n financial_document_type: overrides?.financial_document_type ?? 1,\n deleted: overrides?.deleted ?? 0,\n datetime_add: overrides?.datetime_add || '2025-01-01 00:00:00',\n datetime_alt: overrides?.datetime_alt || '2025-01-01 00:00:00',\n datetime_del: overrides?.datetime_del ?? null,\n}));\n"],"mappings":"AAAA,SAAS,aAAa;AAEtB,SAAS,gBAAgB;AACzB,SAAS,kBAAkB;AAGpB,MAAM,oBAAoB,WAAsC,CAAC,eAAe;AAAA,EACrF,IAAI,WAAW,MAAM,SAAS;AAAA,EAC9B,OAAO,WAAW,SAAS,SAAS;AAAA,EACpC,cAAc,WAAW,gBAAgB;AAAA,EACzC,QAAQ,WAAW,UAAU;AAAA,EAC7B,MAAM,WAAW,QAAQ,MAAM,QAAQ,KAAK;AAAA,EAC5C,UAAU,WAAW,YAAY;AAAA,EACjC,UAAU,WAAW,YAAY;AAAA,EACjC,UAAU,WAAW,YAAY;AAAA,EACjC,UAAU,WAAW,YAAY;AAAA,EACjC,gBAAgB,WAAW,kBAAkB;AAAA,EAC7C,SAAS,WAAW,WAAW;AAAA,EAC/B,qBAAqB,WAAW,uBAAuB;AAAA,EACvD,QAAQ,WAAW,UAAU;AAAA,EAC7B,SAAS,WAAW,WAAW;AAAA,EAC/B,SAAS,WAAW,WAAW;AAAA,EAC/B,gBAAgB,WAAW,kBAAkB;AAAA,EAC7C,oBAAoB,WAAW,sBAAsB;AAAA,EACrD,cAAc,WAAW,gBAAgB;AAAA,EACzC,MAAM,WAAW,QAAQ;AAAA,EACzB,OAAO,WAAW,SAAS;AAAA,EAC3B,SAAS,WAAW,WAAW;AAAA,EAC/B,oBAAoB,WAAW,sBAAsB;AAAA,EACrD,gBAAgB,WAAW,kBAAkB;AAAA,EAC7C,iBAAiB,WAAW,mBAAmB;AAAA,EAC/C,yBAAyB,WAAW,2BAA2B;AAAA,EAC/D,SAAS,WAAW,WAAW;AAAA,EAC/B,cAAc,WAAW,gBAAgB;AAAA,EACzC,cAAc,WAAW,gBAAgB;AAAA,EACzC,cAAc,WAAW,gBAAgB;AAC3C,EAAE;","names":[]}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
const resetters = /* @__PURE__ */ new Set();
|
|
2
|
+
function createMock(factory) {
|
|
3
|
+
let instance = factory();
|
|
4
|
+
resetters.add(() => {
|
|
5
|
+
instance = factory();
|
|
6
|
+
});
|
|
7
|
+
return (overrides) => overrides ? factory(overrides) : instance;
|
|
8
|
+
}
|
|
9
|
+
function resetMocks() {
|
|
10
|
+
for (const reset of resetters) reset();
|
|
11
|
+
}
|
|
12
|
+
export {
|
|
13
|
+
createMock,
|
|
14
|
+
resetMocks
|
|
15
|
+
};
|
|
16
|
+
//# sourceMappingURL=create-mock.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/testing/factories/create-mock.ts"],"sourcesContent":["type Factory<T, O> = (overrides?: O) => T;\n\n// Reset registry for the cached defaults. Runner-agnostic on purpose: these factories also run\n// under `next dev` (E2E request handlers) where vitest's `beforeEach` does not exist, so the app\n// calls `resetMocks()` from its own `beforeEach`.\nconst resetters = new Set<() => void>();\n\n// createMock(factory) returns a getter that:\n// - without overrides → returns the SAME default instance within a test (stable for asserts);\n// - with overrides → returns a NEW instance with those fields replaced.\n// Between tests, `resetMocks()` refreshes the defaults.\nexport function createMock<T, O = Partial<T>>(factory: Factory<T, O>): Factory<T, O> {\n let instance = factory();\n resetters.add(() => {\n instance = factory();\n });\n return (overrides?: O): T => (overrides ? factory(overrides) : instance);\n}\n\n// Refreshes every default cached by createMock. Call it from the setup's beforeEach.\nexport function resetMocks(): void {\n for (const reset of resetters) reset();\n}\n"],"mappings":"AAKA,MAAM,YAAY,oBAAI,IAAgB;AAM/B,SAAS,WAA8B,SAAuC;AACnF,MAAI,WAAW,QAAQ;AACvB,YAAU,IAAI,MAAM;AAClB,eAAW,QAAQ;AAAA,EACrB,CAAC;AACD,SAAO,CAAC,cAAsB,YAAY,QAAQ,SAAS,IAAI;AACjE;AAGO,SAAS,aAAmB;AACjC,aAAW,SAAS,UAAW,OAAM;AACvC;","names":[]}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { createMock, resetMocks } from "./create-mock";
|
|
2
|
+
import { createTestJwt } from "./jwt";
|
|
3
|
+
import { createUserMock } from "./user.factory";
|
|
4
|
+
import { createAccountMock } from "./account.factory";
|
|
5
|
+
import { createWhitelabelMock, createWhitelabelTokenMock } from "./whitelabel.factory";
|
|
6
|
+
import { createSubscriptionMock, createSubscriptionItemMock } from "./subscription.factory";
|
|
7
|
+
import { createPlanMock, createPlanItemMock } from "./plan.factory";
|
|
8
|
+
export {
|
|
9
|
+
createAccountMock,
|
|
10
|
+
createMock,
|
|
11
|
+
createPlanItemMock,
|
|
12
|
+
createPlanMock,
|
|
13
|
+
createSubscriptionItemMock,
|
|
14
|
+
createSubscriptionMock,
|
|
15
|
+
createTestJwt,
|
|
16
|
+
createUserMock,
|
|
17
|
+
createWhitelabelMock,
|
|
18
|
+
createWhitelabelTokenMock,
|
|
19
|
+
resetMocks
|
|
20
|
+
};
|
|
21
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/testing/factories/index.ts"],"sourcesContent":["export { createMock, resetMocks } from './create-mock';\nexport { createTestJwt, type TestJwtClaims } from './jwt';\nexport { createUserMock } from './user.factory';\nexport { createAccountMock } from './account.factory';\nexport { createWhitelabelMock, createWhitelabelTokenMock } from './whitelabel.factory';\nexport { createSubscriptionMock, createSubscriptionItemMock } from './subscription.factory';\nexport { createPlanMock, createPlanItemMock } from './plan.factory';\n"],"mappings":"AAAA,SAAS,YAAY,kBAAkB;AACvC,SAAS,qBAAyC;AAClD,SAAS,sBAAsB;AAC/B,SAAS,yBAAyB;AAClC,SAAS,sBAAsB,iCAAiC;AAChE,SAAS,wBAAwB,kCAAkC;AACnE,SAAS,gBAAgB,0BAA0B;","names":[]}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { TEST_IDS } from "../constants";
|
|
2
|
+
function b64(value) {
|
|
3
|
+
return btoa(JSON.stringify(value));
|
|
4
|
+
}
|
|
5
|
+
function createTestJwt(claims = {}) {
|
|
6
|
+
const payload = {
|
|
7
|
+
session: {
|
|
8
|
+
location: {
|
|
9
|
+
continent: "SA",
|
|
10
|
+
country: claims.country ?? "BR",
|
|
11
|
+
region: "SP",
|
|
12
|
+
city: "Sao Paulo",
|
|
13
|
+
latitude: "0",
|
|
14
|
+
longitude: "0"
|
|
15
|
+
},
|
|
16
|
+
ip: "127.0.0.1",
|
|
17
|
+
timezone: "America/Sao_Paulo",
|
|
18
|
+
agent: "test",
|
|
19
|
+
code: null
|
|
20
|
+
},
|
|
21
|
+
id_wl: String(claims.id_wl ?? TEST_IDS.wl),
|
|
22
|
+
id_account: claims.id_account ?? TEST_IDS.account,
|
|
23
|
+
id_user: claims.id_user ?? TEST_IDS.user,
|
|
24
|
+
iss: "test",
|
|
25
|
+
aud: "test",
|
|
26
|
+
iat: 17e8
|
|
27
|
+
};
|
|
28
|
+
return `${b64({ alg: "none", typ: "JWT" })}.${b64(payload)}.sig`;
|
|
29
|
+
}
|
|
30
|
+
export {
|
|
31
|
+
createTestJwt
|
|
32
|
+
};
|
|
33
|
+
//# sourceMappingURL=jwt.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/testing/factories/jwt.ts"],"sourcesContent":["import type { JWTPayload } from '../../modules/users/schema';\nimport { TEST_IDS } from '../constants';\n\nfunction b64(value: unknown): string {\n // getUserContext decodes the payload with `atob(token.split('.')[1])`, so standard base64 works.\n return btoa(JSON.stringify(value));\n}\n\nexport interface TestJwtClaims {\n id_wl?: number;\n id_account?: number;\n id_user?: number;\n // Country used by resolveLocale (session.location.country).\n country?: string;\n}\n\n// Builds a fake JWT (placeholder signature) whose payload is decodable by getUserContext and\n// resolveLocale. Used as DUMMY_AUTH_TOKEN: the common auth bypasses verification when that env is\n// set, so only the payload matters.\nexport function createTestJwt(claims: TestJwtClaims = {}): string {\n const payload: JWTPayload = {\n session: {\n location: {\n continent: 'SA',\n country: claims.country ?? 'BR',\n region: 'SP',\n city: 'Sao Paulo',\n latitude: '0',\n longitude: '0',\n },\n ip: '127.0.0.1',\n timezone: 'America/Sao_Paulo',\n agent: 'test',\n code: null,\n },\n id_wl: String(claims.id_wl ?? TEST_IDS.wl),\n id_account: claims.id_account ?? TEST_IDS.account,\n id_user: claims.id_user ?? TEST_IDS.user,\n iss: 'test',\n aud: 'test',\n iat: 1700000000,\n };\n return `${b64({ alg: 'none', typ: 'JWT' })}.${b64(payload)}.sig`;\n}\n"],"mappings":"AACA,SAAS,gBAAgB;AAEzB,SAAS,IAAI,OAAwB;AAEnC,SAAO,KAAK,KAAK,UAAU,KAAK,CAAC;AACnC;AAaO,SAAS,cAAc,SAAwB,CAAC,GAAW;AAChE,QAAM,UAAsB;AAAA,IAC1B,SAAS;AAAA,MACP,UAAU;AAAA,QACR,WAAW;AAAA,QACX,SAAS,OAAO,WAAW;AAAA,QAC3B,QAAQ;AAAA,QACR,MAAM;AAAA,QACN,UAAU;AAAA,QACV,WAAW;AAAA,MACb;AAAA,MACA,IAAI;AAAA,MACJ,UAAU;AAAA,MACV,OAAO;AAAA,MACP,MAAM;AAAA,IACR;AAAA,IACA,OAAO,OAAO,OAAO,SAAS,SAAS,EAAE;AAAA,IACzC,YAAY,OAAO,cAAc,SAAS;AAAA,IAC1C,SAAS,OAAO,WAAW,SAAS;AAAA,IACpC,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK;AAAA,EACP;AACA,SAAO,GAAG,IAAI,EAAE,KAAK,QAAQ,KAAK,MAAM,CAAC,CAAC,IAAI,IAAI,OAAO,CAAC;AAC5D;","names":[]}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { faker } from "@faker-js/faker";
|
|
2
|
+
import { createMock } from "./create-mock";
|
|
3
|
+
const createPlanItemMock = createMock((overrides) => ({
|
|
4
|
+
id_addon: overrides?.id_addon ?? 2,
|
|
5
|
+
quantity: overrides?.quantity ?? 10,
|
|
6
|
+
value: overrides?.value ?? 9990,
|
|
7
|
+
base: overrides?.base ?? true
|
|
8
|
+
}));
|
|
9
|
+
const createPlanMock = createMock((overrides) => ({
|
|
10
|
+
id: overrides?.id ?? faker.number.int({ min: 1, max: 9999 }),
|
|
11
|
+
name: overrides?.name || faker.commerce.productName(),
|
|
12
|
+
value: overrides?.value ?? 9990,
|
|
13
|
+
currency: overrides?.currency ?? "brl",
|
|
14
|
+
type: overrides?.type ?? "paid",
|
|
15
|
+
discount_semester: overrides?.discount_semester ?? 0,
|
|
16
|
+
discount_annual: overrides?.discount_annual ?? 0,
|
|
17
|
+
items: overrides?.items ?? [createPlanItemMock()]
|
|
18
|
+
}));
|
|
19
|
+
export {
|
|
20
|
+
createPlanItemMock,
|
|
21
|
+
createPlanMock
|
|
22
|
+
};
|
|
23
|
+
//# sourceMappingURL=plan.factory.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/testing/factories/plan.factory.ts"],"sourcesContent":["import { faker } from '@faker-js/faker';\nimport { Plan, PlanItem } from '../../modules/plans/types/plan.type';\nimport { createMock } from './create-mock';\n\nexport const createPlanItemMock = createMock<PlanItem, Partial<PlanItem>>((overrides) => ({\n id_addon: overrides?.id_addon ?? 2,\n quantity: overrides?.quantity ?? 10,\n value: overrides?.value ?? 9990,\n base: overrides?.base ?? true,\n}));\n\nexport const createPlanMock = createMock<Plan, Partial<Plan>>((overrides) => ({\n id: overrides?.id ?? faker.number.int({ min: 1, max: 9999 }),\n name: overrides?.name || faker.commerce.productName(),\n value: overrides?.value ?? 9990,\n currency: overrides?.currency ?? 'brl',\n type: overrides?.type ?? 'paid',\n discount_semester: overrides?.discount_semester ?? 0,\n discount_annual: overrides?.discount_annual ?? 0,\n items: overrides?.items ?? [createPlanItemMock()],\n}));\n"],"mappings":"AAAA,SAAS,aAAa;AAEtB,SAAS,kBAAkB;AAEpB,MAAM,qBAAqB,WAAwC,CAAC,eAAe;AAAA,EACxF,UAAU,WAAW,YAAY;AAAA,EACjC,UAAU,WAAW,YAAY;AAAA,EACjC,OAAO,WAAW,SAAS;AAAA,EAC3B,MAAM,WAAW,QAAQ;AAC3B,EAAE;AAEK,MAAM,iBAAiB,WAAgC,CAAC,eAAe;AAAA,EAC5E,IAAI,WAAW,MAAM,MAAM,OAAO,IAAI,EAAE,KAAK,GAAG,KAAK,KAAK,CAAC;AAAA,EAC3D,MAAM,WAAW,QAAQ,MAAM,SAAS,YAAY;AAAA,EACpD,OAAO,WAAW,SAAS;AAAA,EAC3B,UAAU,WAAW,YAAY;AAAA,EACjC,MAAM,WAAW,QAAQ;AAAA,EACzB,mBAAmB,WAAW,qBAAqB;AAAA,EACnD,iBAAiB,WAAW,mBAAmB;AAAA,EAC/C,OAAO,WAAW,SAAS,CAAC,mBAAmB,CAAC;AAClD,EAAE;","names":[]}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { faker } from "@faker-js/faker";
|
|
2
|
+
import { TEST_IDS } from "../constants";
|
|
3
|
+
import { createMock } from "./create-mock";
|
|
4
|
+
const createSubscriptionItemMock = createMock(
|
|
5
|
+
(overrides) => ({
|
|
6
|
+
id: overrides?.id ?? faker.number.int({ min: 1, max: 99999 }),
|
|
7
|
+
deleted: overrides?.deleted ?? 0,
|
|
8
|
+
datetime_add: overrides?.datetime_add ?? /* @__PURE__ */ new Date("2025-01-01T00:00:00Z"),
|
|
9
|
+
id_wl: overrides?.id_wl ?? TEST_IDS.wl,
|
|
10
|
+
id_subscription: overrides?.id_subscription ?? 1,
|
|
11
|
+
id_addon: overrides?.id_addon ?? null,
|
|
12
|
+
value: overrides?.value ?? 9990,
|
|
13
|
+
currency: overrides?.currency ?? "brl",
|
|
14
|
+
quantity: overrides?.quantity ?? 1,
|
|
15
|
+
payment_status: overrides?.payment_status ?? 1,
|
|
16
|
+
id_charge: overrides?.id_charge ?? null,
|
|
17
|
+
trial: overrides?.trial ?? true
|
|
18
|
+
})
|
|
19
|
+
);
|
|
20
|
+
const createSubscriptionMock = createMock(
|
|
21
|
+
(overrides) => ({
|
|
22
|
+
id: overrides?.id ?? faker.number.int({ min: 1, max: 99999 }),
|
|
23
|
+
deleted: overrides?.deleted ?? 0,
|
|
24
|
+
datetime_add: overrides?.datetime_add ?? /* @__PURE__ */ new Date("2025-01-01T00:00:00Z"),
|
|
25
|
+
id_wl: overrides?.id_wl ?? TEST_IDS.wl,
|
|
26
|
+
id_account: overrides?.id_account ?? TEST_IDS.account,
|
|
27
|
+
id_card: overrides?.id_card ?? null,
|
|
28
|
+
id_coupon: overrides?.id_coupon ?? null,
|
|
29
|
+
type: overrides?.type ?? "recurring",
|
|
30
|
+
payment_method: overrides?.payment_method ?? 1,
|
|
31
|
+
periodicity: overrides?.periodicity ?? 1,
|
|
32
|
+
value: overrides?.value ?? 9990,
|
|
33
|
+
id_product: overrides?.id_product ?? 1,
|
|
34
|
+
id_plan: overrides?.id_plan ?? 1,
|
|
35
|
+
id_gateway: overrides?.id_gateway ?? null,
|
|
36
|
+
gateway_account: overrides?.gateway_account ?? null,
|
|
37
|
+
date_hiring: overrides?.date_hiring ?? /* @__PURE__ */ new Date("2025-01-01"),
|
|
38
|
+
date_due: overrides?.date_due ?? /* @__PURE__ */ new Date("2099-01-01"),
|
|
39
|
+
date_cancellation: overrides?.date_cancellation ?? null,
|
|
40
|
+
date_verification: overrides?.date_verification ?? null,
|
|
41
|
+
cancellation_reason: overrides?.cancellation_reason ?? null,
|
|
42
|
+
cancellation_description: overrides?.cancellation_description ?? null,
|
|
43
|
+
active: overrides?.active ?? true,
|
|
44
|
+
charged: overrides?.charged ?? true,
|
|
45
|
+
items: overrides?.items ?? [createSubscriptionItemMock()]
|
|
46
|
+
})
|
|
47
|
+
);
|
|
48
|
+
export {
|
|
49
|
+
createSubscriptionItemMock,
|
|
50
|
+
createSubscriptionMock
|
|
51
|
+
};
|
|
52
|
+
//# sourceMappingURL=subscription.factory.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/testing/factories/subscription.factory.ts"],"sourcesContent":["import { faker } from '@faker-js/faker';\nimport { Subscription, SubscriptionItem } from '../../modules/subscriptions/types/subscription.type';\nimport { TEST_IDS } from '../constants';\nimport { createMock } from './create-mock';\n\n// Dates are Date objects (the inferred output of the schema).\nexport const createSubscriptionItemMock = createMock<SubscriptionItem, Partial<SubscriptionItem>>(\n (overrides) => ({\n id: overrides?.id ?? faker.number.int({ min: 1, max: 99999 }),\n deleted: overrides?.deleted ?? 0,\n datetime_add: overrides?.datetime_add ?? new Date('2025-01-01T00:00:00Z'),\n id_wl: overrides?.id_wl ?? TEST_IDS.wl,\n id_subscription: overrides?.id_subscription ?? 1,\n id_addon: overrides?.id_addon ?? null,\n value: overrides?.value ?? 9990,\n currency: overrides?.currency ?? 'brl',\n quantity: overrides?.quantity ?? 1,\n payment_status: overrides?.payment_status ?? 1,\n id_charge: overrides?.id_charge ?? null,\n trial: overrides?.trial ?? true,\n }),\n);\n\n// Default: an active subscription with a future due date (a valid trial).\nexport const createSubscriptionMock = createMock<Subscription, Partial<Subscription>>(\n (overrides) => ({\n id: overrides?.id ?? faker.number.int({ min: 1, max: 99999 }),\n deleted: overrides?.deleted ?? 0,\n datetime_add: overrides?.datetime_add ?? new Date('2025-01-01T00:00:00Z'),\n id_wl: overrides?.id_wl ?? TEST_IDS.wl,\n id_account: overrides?.id_account ?? TEST_IDS.account,\n id_card: overrides?.id_card ?? null,\n id_coupon: overrides?.id_coupon ?? null,\n type: overrides?.type ?? 'recurring',\n payment_method: overrides?.payment_method ?? 1,\n periodicity: overrides?.periodicity ?? 1,\n value: overrides?.value ?? 9990,\n id_product: overrides?.id_product ?? 1,\n id_plan: overrides?.id_plan ?? 1,\n id_gateway: overrides?.id_gateway ?? null,\n gateway_account: overrides?.gateway_account ?? null,\n date_hiring: overrides?.date_hiring ?? new Date('2025-01-01'),\n date_due: overrides?.date_due ?? new Date('2099-01-01'),\n date_cancellation: overrides?.date_cancellation ?? null,\n date_verification: overrides?.date_verification ?? null,\n cancellation_reason: overrides?.cancellation_reason ?? null,\n cancellation_description: overrides?.cancellation_description ?? null,\n active: overrides?.active ?? true,\n charged: overrides?.charged ?? true,\n items: overrides?.items ?? [createSubscriptionItemMock()],\n }),\n);\n"],"mappings":"AAAA,SAAS,aAAa;AAEtB,SAAS,gBAAgB;AACzB,SAAS,kBAAkB;AAGpB,MAAM,6BAA6B;AAAA,EACxC,CAAC,eAAe;AAAA,IACd,IAAI,WAAW,MAAM,MAAM,OAAO,IAAI,EAAE,KAAK,GAAG,KAAK,MAAM,CAAC;AAAA,IAC5D,SAAS,WAAW,WAAW;AAAA,IAC/B,cAAc,WAAW,gBAAgB,oBAAI,KAAK,sBAAsB;AAAA,IACxE,OAAO,WAAW,SAAS,SAAS;AAAA,IACpC,iBAAiB,WAAW,mBAAmB;AAAA,IAC/C,UAAU,WAAW,YAAY;AAAA,IACjC,OAAO,WAAW,SAAS;AAAA,IAC3B,UAAU,WAAW,YAAY;AAAA,IACjC,UAAU,WAAW,YAAY;AAAA,IACjC,gBAAgB,WAAW,kBAAkB;AAAA,IAC7C,WAAW,WAAW,aAAa;AAAA,IACnC,OAAO,WAAW,SAAS;AAAA,EAC7B;AACF;AAGO,MAAM,yBAAyB;AAAA,EACpC,CAAC,eAAe;AAAA,IACd,IAAI,WAAW,MAAM,MAAM,OAAO,IAAI,EAAE,KAAK,GAAG,KAAK,MAAM,CAAC;AAAA,IAC5D,SAAS,WAAW,WAAW;AAAA,IAC/B,cAAc,WAAW,gBAAgB,oBAAI,KAAK,sBAAsB;AAAA,IACxE,OAAO,WAAW,SAAS,SAAS;AAAA,IACpC,YAAY,WAAW,cAAc,SAAS;AAAA,IAC9C,SAAS,WAAW,WAAW;AAAA,IAC/B,WAAW,WAAW,aAAa;AAAA,IACnC,MAAM,WAAW,QAAQ;AAAA,IACzB,gBAAgB,WAAW,kBAAkB;AAAA,IAC7C,aAAa,WAAW,eAAe;AAAA,IACvC,OAAO,WAAW,SAAS;AAAA,IAC3B,YAAY,WAAW,cAAc;AAAA,IACrC,SAAS,WAAW,WAAW;AAAA,IAC/B,YAAY,WAAW,cAAc;AAAA,IACrC,iBAAiB,WAAW,mBAAmB;AAAA,IAC/C,aAAa,WAAW,eAAe,oBAAI,KAAK,YAAY;AAAA,IAC5D,UAAU,WAAW,YAAY,oBAAI,KAAK,YAAY;AAAA,IACtD,mBAAmB,WAAW,qBAAqB;AAAA,IACnD,mBAAmB,WAAW,qBAAqB;AAAA,IACnD,qBAAqB,WAAW,uBAAuB;AAAA,IACvD,0BAA0B,WAAW,4BAA4B;AAAA,IACjE,QAAQ,WAAW,UAAU;AAAA,IAC7B,SAAS,WAAW,WAAW;AAAA,IAC/B,OAAO,WAAW,SAAS,CAAC,2BAA2B,CAAC;AAAA,EAC1D;AACF;","names":[]}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { faker } from "@faker-js/faker";
|
|
2
|
+
import { UserProfile } from "../../modules/users/schema";
|
|
3
|
+
import { TEST_IDS } from "../constants";
|
|
4
|
+
import { createMock } from "./create-mock";
|
|
5
|
+
const createUserMock = createMock((overrides) => ({
|
|
6
|
+
id: overrides?.id ?? TEST_IDS.user,
|
|
7
|
+
id_wl: overrides?.id_wl ?? TEST_IDS.wl,
|
|
8
|
+
id_account: overrides?.id_account ?? TEST_IDS.account,
|
|
9
|
+
id_api: overrides?.id_api ?? 1,
|
|
10
|
+
name: overrides?.name || faker.person.firstName(),
|
|
11
|
+
last_name: overrides?.last_name || faker.person.lastName(),
|
|
12
|
+
email: overrides?.email || faker.internet.email().toLowerCase(),
|
|
13
|
+
ddi: overrides?.ddi || "55",
|
|
14
|
+
phone: overrides?.phone || faker.string.numeric(11),
|
|
15
|
+
rg: overrides?.rg ?? null,
|
|
16
|
+
cpf: overrides?.cpf ?? null,
|
|
17
|
+
gender: overrides?.gender ?? 0,
|
|
18
|
+
two_factor_authentication: overrides?.two_factor_authentication ?? false,
|
|
19
|
+
google_sub: overrides?.google_sub ?? null,
|
|
20
|
+
google_linked_at: overrides?.google_linked_at ?? null,
|
|
21
|
+
profile: overrides?.profile ?? UserProfile.owner,
|
|
22
|
+
language: overrides?.language ?? "pt-br",
|
|
23
|
+
receive_sms: overrides?.receive_sms ?? false,
|
|
24
|
+
receive_email: overrides?.receive_email ?? true,
|
|
25
|
+
photo: overrides?.photo ?? null,
|
|
26
|
+
deleted: overrides?.deleted ?? 0,
|
|
27
|
+
datetime_alt: overrides?.datetime_alt || "2025-01-01 00:00:00",
|
|
28
|
+
datetime_del: overrides?.datetime_del ?? null,
|
|
29
|
+
datetime_add: overrides?.datetime_add || "2025-01-01 00:00:00",
|
|
30
|
+
total_projects: overrides?.total_projects ?? 1,
|
|
31
|
+
projects: overrides?.projects ?? [{ id: 1, title: faker.company.name() }]
|
|
32
|
+
}));
|
|
33
|
+
export {
|
|
34
|
+
createUserMock
|
|
35
|
+
};
|
|
36
|
+
//# sourceMappingURL=user.factory.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/testing/factories/user.factory.ts"],"sourcesContent":["import { faker } from '@faker-js/faker';\nimport { User, UserProfile } from '../../modules/users/schema';\nimport { TEST_IDS } from '../constants';\nimport { createMock } from './create-mock';\n\n// Identity fields (id/id_wl/id_account) are fixed to TEST_IDS by default — the auth chain and the\n// request-URL matching depend on them; override explicitly when needed. Cosmetic fields use faker.\nexport const createUserMock = createMock<User, Partial<User>>((overrides) => ({\n id: overrides?.id ?? TEST_IDS.user,\n id_wl: overrides?.id_wl ?? TEST_IDS.wl,\n id_account: overrides?.id_account ?? TEST_IDS.account,\n id_api: overrides?.id_api ?? 1,\n name: overrides?.name || faker.person.firstName(),\n last_name: overrides?.last_name || faker.person.lastName(),\n email: overrides?.email || faker.internet.email().toLowerCase(),\n ddi: overrides?.ddi || '55',\n phone: overrides?.phone || faker.string.numeric(11),\n rg: overrides?.rg ?? null,\n cpf: overrides?.cpf ?? null,\n gender: overrides?.gender ?? 0,\n two_factor_authentication: overrides?.two_factor_authentication ?? false,\n google_sub: overrides?.google_sub ?? null,\n google_linked_at: overrides?.google_linked_at ?? null,\n profile: overrides?.profile ?? UserProfile.owner,\n language: overrides?.language ?? 'pt-br',\n receive_sms: overrides?.receive_sms ?? false,\n receive_email: overrides?.receive_email ?? true,\n photo: overrides?.photo ?? null,\n deleted: overrides?.deleted ?? 0,\n datetime_alt: overrides?.datetime_alt || '2025-01-01 00:00:00',\n datetime_del: overrides?.datetime_del ?? null,\n datetime_add: overrides?.datetime_add || '2025-01-01 00:00:00',\n total_projects: overrides?.total_projects ?? 1,\n projects: overrides?.projects ?? [{ id: 1, title: faker.company.name() }],\n}));\n"],"mappings":"AAAA,SAAS,aAAa;AACtB,SAAe,mBAAmB;AAClC,SAAS,gBAAgB;AACzB,SAAS,kBAAkB;AAIpB,MAAM,iBAAiB,WAAgC,CAAC,eAAe;AAAA,EAC5E,IAAI,WAAW,MAAM,SAAS;AAAA,EAC9B,OAAO,WAAW,SAAS,SAAS;AAAA,EACpC,YAAY,WAAW,cAAc,SAAS;AAAA,EAC9C,QAAQ,WAAW,UAAU;AAAA,EAC7B,MAAM,WAAW,QAAQ,MAAM,OAAO,UAAU;AAAA,EAChD,WAAW,WAAW,aAAa,MAAM,OAAO,SAAS;AAAA,EACzD,OAAO,WAAW,SAAS,MAAM,SAAS,MAAM,EAAE,YAAY;AAAA,EAC9D,KAAK,WAAW,OAAO;AAAA,EACvB,OAAO,WAAW,SAAS,MAAM,OAAO,QAAQ,EAAE;AAAA,EAClD,IAAI,WAAW,MAAM;AAAA,EACrB,KAAK,WAAW,OAAO;AAAA,EACvB,QAAQ,WAAW,UAAU;AAAA,EAC7B,2BAA2B,WAAW,6BAA6B;AAAA,EACnE,YAAY,WAAW,cAAc;AAAA,EACrC,kBAAkB,WAAW,oBAAoB;AAAA,EACjD,SAAS,WAAW,WAAW,YAAY;AAAA,EAC3C,UAAU,WAAW,YAAY;AAAA,EACjC,aAAa,WAAW,eAAe;AAAA,EACvC,eAAe,WAAW,iBAAiB;AAAA,EAC3C,OAAO,WAAW,SAAS;AAAA,EAC3B,SAAS,WAAW,WAAW;AAAA,EAC/B,cAAc,WAAW,gBAAgB;AAAA,EACzC,cAAc,WAAW,gBAAgB;AAAA,EACzC,cAAc,WAAW,gBAAgB;AAAA,EACzC,gBAAgB,WAAW,kBAAkB;AAAA,EAC7C,UAAU,WAAW,YAAY,CAAC,EAAE,IAAI,GAAG,OAAO,MAAM,QAAQ,KAAK,EAAE,CAAC;AAC1E,EAAE;","names":[]}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { faker } from "@faker-js/faker";
|
|
2
|
+
import { TEST_API, TEST_IDS } from "../constants";
|
|
3
|
+
import { createMock } from "./create-mock";
|
|
4
|
+
import { createTestJwt } from "./jwt";
|
|
5
|
+
const createWhitelabelMock = createMock(
|
|
6
|
+
(overrides) => {
|
|
7
|
+
const domain = overrides?.domain ?? TEST_API.domain;
|
|
8
|
+
return {
|
|
9
|
+
id: overrides?.id ?? TEST_IDS.wl,
|
|
10
|
+
deleted: overrides?.deleted ?? 0,
|
|
11
|
+
datetime_alt: overrides?.datetime_alt || "2025-01-01 00:00:00",
|
|
12
|
+
datetime_del: overrides?.datetime_del ?? null,
|
|
13
|
+
datetime_add: overrides?.datetime_add || "2025-01-01 00:00:00",
|
|
14
|
+
id_account: overrides?.id_account ?? TEST_IDS.account,
|
|
15
|
+
active: overrides?.active ?? true,
|
|
16
|
+
name: overrides?.name || faker.company.name(),
|
|
17
|
+
email: overrides?.email || faker.internet.email().toLowerCase(),
|
|
18
|
+
email_financial: overrides?.email_financial || faker.internet.email().toLowerCase(),
|
|
19
|
+
email_transactional: overrides?.email_transactional || faker.internet.email().toLowerCase(),
|
|
20
|
+
domain,
|
|
21
|
+
domain_free: overrides?.domain_free ?? null,
|
|
22
|
+
url_help: overrides?.url_help ?? `https://${domain}/help`,
|
|
23
|
+
url_login: overrides?.url_login ?? `https://${domain}/login`,
|
|
24
|
+
url_site: overrides?.url_site ?? `https://${domain}`,
|
|
25
|
+
url_signup: overrides?.url_signup ?? `https://${domain}/signup`,
|
|
26
|
+
codes: overrides?.codes ?? null,
|
|
27
|
+
id_gateway: overrides?.id_gateway ?? 1,
|
|
28
|
+
gateway_product: overrides?.gateway_product ?? "prod_test",
|
|
29
|
+
external_contracting: overrides?.external_contracting ?? false,
|
|
30
|
+
logo: overrides?.logo ?? `https://${domain}/logo.png`,
|
|
31
|
+
secondary_logo: overrides?.secondary_logo ?? null,
|
|
32
|
+
favicon: overrides?.favicon ?? `https://${domain}/favicon.ico`,
|
|
33
|
+
general: overrides?.general ?? {
|
|
34
|
+
primary_color: faker.color.rgb(),
|
|
35
|
+
hover_color: faker.color.rgb(),
|
|
36
|
+
link_color: faker.color.rgb()
|
|
37
|
+
},
|
|
38
|
+
signin_page: overrides?.signin_page ?? null,
|
|
39
|
+
signup_page: overrides?.signup_page ?? null,
|
|
40
|
+
dashboard: overrides?.dashboard ?? null,
|
|
41
|
+
use_policy_url: overrides?.use_policy_url ?? `https://${domain}/terms`,
|
|
42
|
+
cookie_policy_url: overrides?.cookie_policy_url ?? `https://${domain}/cookies`,
|
|
43
|
+
privacy_policy_url: overrides?.privacy_policy_url ?? `https://${domain}/privacy`,
|
|
44
|
+
editor_url: overrides?.editor_url ?? `https://editor.${domain}`,
|
|
45
|
+
accounts_url: overrides?.accounts_url ?? `https://accounts.${domain}`,
|
|
46
|
+
pages_url: overrides?.pages_url ?? `https://pages.${domain}`,
|
|
47
|
+
pages_preview_url: overrides?.pages_preview_url ?? `https://preview.${domain}`,
|
|
48
|
+
api_url: overrides?.api_url ?? TEST_API.gpages,
|
|
49
|
+
cname_url: overrides?.cname_url ?? `cname.${domain}`,
|
|
50
|
+
video_url: overrides?.video_url ?? null,
|
|
51
|
+
external_contracting_url: overrides?.external_contracting_url ?? null,
|
|
52
|
+
external_plans_url: overrides?.external_plans_url ?? null
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
);
|
|
56
|
+
const createWhitelabelTokenMock = createMock(
|
|
57
|
+
(overrides) => ({
|
|
58
|
+
...createWhitelabelMock(overrides),
|
|
59
|
+
token: overrides?.token ?? createTestJwt()
|
|
60
|
+
})
|
|
61
|
+
);
|
|
62
|
+
export {
|
|
63
|
+
createWhitelabelMock,
|
|
64
|
+
createWhitelabelTokenMock
|
|
65
|
+
};
|
|
66
|
+
//# sourceMappingURL=whitelabel.factory.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/testing/factories/whitelabel.factory.ts"],"sourcesContent":["import { faker } from '@faker-js/faker';\nimport { WhitelabelData, WhitelabelTokenData } from '../../modules/whitelabel/schema';\nimport { TEST_API, TEST_IDS } from '../constants';\nimport { createMock } from './create-mock';\nimport { createTestJwt } from './jwt';\n\n// id/domain stay aligned with TEST_IDS/TEST_API because resolveLocale/branding and the\n// domain-based whitelabel resolution depend on them.\nexport const createWhitelabelMock = createMock<WhitelabelData, Partial<WhitelabelData>>(\n (overrides) => {\n const domain = overrides?.domain ?? TEST_API.domain;\n return {\n id: overrides?.id ?? TEST_IDS.wl,\n deleted: overrides?.deleted ?? 0,\n datetime_alt: overrides?.datetime_alt || '2025-01-01 00:00:00',\n datetime_del: overrides?.datetime_del ?? null,\n datetime_add: overrides?.datetime_add || '2025-01-01 00:00:00',\n id_account: overrides?.id_account ?? TEST_IDS.account,\n active: overrides?.active ?? true,\n name: overrides?.name || faker.company.name(),\n email: overrides?.email || faker.internet.email().toLowerCase(),\n email_financial: overrides?.email_financial || faker.internet.email().toLowerCase(),\n email_transactional: overrides?.email_transactional || faker.internet.email().toLowerCase(),\n domain,\n domain_free: overrides?.domain_free ?? null,\n url_help: overrides?.url_help ?? `https://${domain}/help`,\n url_login: overrides?.url_login ?? `https://${domain}/login`,\n url_site: overrides?.url_site ?? `https://${domain}`,\n url_signup: overrides?.url_signup ?? `https://${domain}/signup`,\n codes: overrides?.codes ?? null,\n id_gateway: overrides?.id_gateway ?? 1,\n gateway_product: overrides?.gateway_product ?? 'prod_test',\n external_contracting: overrides?.external_contracting ?? false,\n logo: overrides?.logo ?? `https://${domain}/logo.png`,\n secondary_logo: overrides?.secondary_logo ?? null,\n favicon: overrides?.favicon ?? `https://${domain}/favicon.ico`,\n general: overrides?.general ?? {\n primary_color: faker.color.rgb(),\n hover_color: faker.color.rgb(),\n link_color: faker.color.rgb(),\n },\n signin_page: overrides?.signin_page ?? null,\n signup_page: overrides?.signup_page ?? null,\n dashboard: overrides?.dashboard ?? null,\n use_policy_url: overrides?.use_policy_url ?? `https://${domain}/terms`,\n cookie_policy_url: overrides?.cookie_policy_url ?? `https://${domain}/cookies`,\n privacy_policy_url: overrides?.privacy_policy_url ?? `https://${domain}/privacy`,\n editor_url: overrides?.editor_url ?? `https://editor.${domain}`,\n accounts_url: overrides?.accounts_url ?? `https://accounts.${domain}`,\n pages_url: overrides?.pages_url ?? `https://pages.${domain}`,\n pages_preview_url: overrides?.pages_preview_url ?? `https://preview.${domain}`,\n api_url: overrides?.api_url ?? TEST_API.gpages,\n cname_url: overrides?.cname_url ?? `cname.${domain}`,\n video_url: overrides?.video_url ?? null,\n external_contracting_url: overrides?.external_contracting_url ?? null,\n external_plans_url: overrides?.external_plans_url ?? null,\n };\n },\n);\n\n// Variant with `token` — what getTokenByDomain returns for the ApiClient to build the header.\nexport const createWhitelabelTokenMock = createMock<WhitelabelTokenData, Partial<WhitelabelTokenData>>(\n (overrides) => ({\n ...createWhitelabelMock(overrides),\n token: overrides?.token ?? createTestJwt(),\n }),\n);\n"],"mappings":"AAAA,SAAS,aAAa;AAEtB,SAAS,UAAU,gBAAgB;AACnC,SAAS,kBAAkB;AAC3B,SAAS,qBAAqB;AAIvB,MAAM,uBAAuB;AAAA,EAClC,CAAC,cAAc;AACb,UAAM,SAAS,WAAW,UAAU,SAAS;AAC7C,WAAO;AAAA,MACL,IAAI,WAAW,MAAM,SAAS;AAAA,MAC9B,SAAS,WAAW,WAAW;AAAA,MAC/B,cAAc,WAAW,gBAAgB;AAAA,MACzC,cAAc,WAAW,gBAAgB;AAAA,MACzC,cAAc,WAAW,gBAAgB;AAAA,MACzC,YAAY,WAAW,cAAc,SAAS;AAAA,MAC9C,QAAQ,WAAW,UAAU;AAAA,MAC7B,MAAM,WAAW,QAAQ,MAAM,QAAQ,KAAK;AAAA,MAC5C,OAAO,WAAW,SAAS,MAAM,SAAS,MAAM,EAAE,YAAY;AAAA,MAC9D,iBAAiB,WAAW,mBAAmB,MAAM,SAAS,MAAM,EAAE,YAAY;AAAA,MAClF,qBAAqB,WAAW,uBAAuB,MAAM,SAAS,MAAM,EAAE,YAAY;AAAA,MAC1F;AAAA,MACA,aAAa,WAAW,eAAe;AAAA,MACvC,UAAU,WAAW,YAAY,WAAW,MAAM;AAAA,MAClD,WAAW,WAAW,aAAa,WAAW,MAAM;AAAA,MACpD,UAAU,WAAW,YAAY,WAAW,MAAM;AAAA,MAClD,YAAY,WAAW,cAAc,WAAW,MAAM;AAAA,MACtD,OAAO,WAAW,SAAS;AAAA,MAC3B,YAAY,WAAW,cAAc;AAAA,MACrC,iBAAiB,WAAW,mBAAmB;AAAA,MAC/C,sBAAsB,WAAW,wBAAwB;AAAA,MACzD,MAAM,WAAW,QAAQ,WAAW,MAAM;AAAA,MAC1C,gBAAgB,WAAW,kBAAkB;AAAA,MAC7C,SAAS,WAAW,WAAW,WAAW,MAAM;AAAA,MAChD,SAAS,WAAW,WAAW;AAAA,QAC7B,eAAe,MAAM,MAAM,IAAI;AAAA,QAC/B,aAAa,MAAM,MAAM,IAAI;AAAA,QAC7B,YAAY,MAAM,MAAM,IAAI;AAAA,MAC9B;AAAA,MACA,aAAa,WAAW,eAAe;AAAA,MACvC,aAAa,WAAW,eAAe;AAAA,MACvC,WAAW,WAAW,aAAa;AAAA,MACnC,gBAAgB,WAAW,kBAAkB,WAAW,MAAM;AAAA,MAC9D,mBAAmB,WAAW,qBAAqB,WAAW,MAAM;AAAA,MACpE,oBAAoB,WAAW,sBAAsB,WAAW,MAAM;AAAA,MACtE,YAAY,WAAW,cAAc,kBAAkB,MAAM;AAAA,MAC7D,cAAc,WAAW,gBAAgB,oBAAoB,MAAM;AAAA,MACnE,WAAW,WAAW,aAAa,iBAAiB,MAAM;AAAA,MAC1D,mBAAmB,WAAW,qBAAqB,mBAAmB,MAAM;AAAA,MAC5E,SAAS,WAAW,WAAW,SAAS;AAAA,MACxC,WAAW,WAAW,aAAa,SAAS,MAAM;AAAA,MAClD,WAAW,WAAW,aAAa;AAAA,MACnC,0BAA0B,WAAW,4BAA4B;AAAA,MACjE,oBAAoB,WAAW,sBAAsB;AAAA,IACvD;AAAA,EACF;AACF;AAGO,MAAM,4BAA4B;AAAA,EACvC,CAAC,eAAe;AAAA,IACd,GAAG,qBAAqB,SAAS;AAAA,IACjC,OAAO,WAAW,SAAS,cAAc;AAAA,EAC3C;AACF;","names":[]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/testing/index.ts"],"sourcesContent":["// Shared test infra for the GreatApps apps. Imported as `@greatapps/common/testing`.\n//\n// This barrel is LIGHT and safe for node/E2E/handlers: only deterministic factories and session\n// request handlers. The React PROVIDERS (which pull the lib's client tree) live in a separate\n// subpath — `@greatapps/common/testing/react` — so the barrel and its load-time side effects\n// (e.g. zustand stores reading localStorage) don't leak into reducer/route-handler tests.\n//\n// `msw` and `@faker-js/faker` are OPTIONAL peer dependencies: only the files here import them.\nexport { TEST_IDS, TEST_API, TEST_API_VERSION, TEST_API_LOCALE } from './constants';\nexport * from './factories';\nexport * from './msw';\n"],"mappings":"AAQA,SAAS,UAAU,UAAU,kBAAkB,uBAAuB;AACtE,cAAc;AACd,cAAc;","names":[]}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { HttpResponse } from "msw";
|
|
2
|
+
function apiList(items, total = items.length) {
|
|
3
|
+
return HttpResponse.json({ status: 1, data: items, total });
|
|
4
|
+
}
|
|
5
|
+
function apiFind(item) {
|
|
6
|
+
return apiList([item], 1);
|
|
7
|
+
}
|
|
8
|
+
function apiOne(data) {
|
|
9
|
+
return HttpResponse.json({ status: 1, data });
|
|
10
|
+
}
|
|
11
|
+
function apiError(message = "test error", status = 400) {
|
|
12
|
+
return HttpResponse.json({ status: 0, message }, { status });
|
|
13
|
+
}
|
|
14
|
+
export {
|
|
15
|
+
apiError,
|
|
16
|
+
apiFind,
|
|
17
|
+
apiList,
|
|
18
|
+
apiOne
|
|
19
|
+
};
|
|
20
|
+
//# sourceMappingURL=envelope.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/testing/msw/envelope.ts"],"sourcesContent":["import { HttpResponse } from 'msw';\n\n// The envelope GreatApps backends return. Services read `data` as an array and take `data[0]` on\n// finds (see the user/account/whitelabel/pages services), so the success default is a list. Use\n// `apiOne` when the consumer expects `data` to be a single object.\nexport function apiList<T>(items: T[], total = items.length) {\n return HttpResponse.json({ status: 1, data: items, total });\n}\n\n// Success with a single item wrapped in a list (`{ status:1, data:[item], total:1 }`).\nexport function apiFind<T>(item: T) {\n return apiList([item], 1);\n}\n\n// Success with `data` as a single object (few endpoints; most use a list).\nexport function apiOne<T>(data: T) {\n return HttpResponse.json({ status: 1, data });\n}\n\n// Backend-shaped error (`{ status:0, message }`) with an HTTP status.\nexport function apiError(message = 'test error', status = 400) {\n return HttpResponse.json({ status: 0, message }, { status });\n}\n"],"mappings":"AAAA,SAAS,oBAAoB;AAKtB,SAAS,QAAW,OAAY,QAAQ,MAAM,QAAQ;AAC3D,SAAO,aAAa,KAAK,EAAE,QAAQ,GAAG,MAAM,OAAO,MAAM,CAAC;AAC5D;AAGO,SAAS,QAAW,MAAS;AAClC,SAAO,QAAQ,CAAC,IAAI,GAAG,CAAC;AAC1B;AAGO,SAAS,OAAU,MAAS;AACjC,SAAO,aAAa,KAAK,EAAE,QAAQ,GAAG,KAAK,CAAC;AAC9C;AAGO,SAAS,SAAS,UAAU,cAAc,SAAS,KAAK;AAC7D,SAAO,aAAa,KAAK,EAAE,QAAQ,GAAG,QAAQ,GAAG,EAAE,OAAO,CAAC;AAC7D;","names":[]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/testing/msw/index.ts"],"sourcesContent":["export { apiList, apiFind, apiOne, apiError } from './envelope';\nexport { makeSessionHandlers, type SessionHandlersOptions } from './session.handlers';\n"],"mappings":"AAAA,SAAS,SAAS,SAAS,QAAQ,gBAAgB;AACnD,SAAS,2BAAwD;","names":[]}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { http } from "msw";
|
|
2
|
+
import { TEST_API } from "../constants";
|
|
3
|
+
import { createAccountMock } from "../factories/account.factory";
|
|
4
|
+
import { createUserMock } from "../factories/user.factory";
|
|
5
|
+
import { createWhitelabelTokenMock } from "../factories/whitelabel.factory";
|
|
6
|
+
import { apiFind } from "./envelope";
|
|
7
|
+
function makeSessionHandlers(opts = {}) {
|
|
8
|
+
const base = opts.gappsBase ?? TEST_API.gapps;
|
|
9
|
+
const user = opts.user ?? createUserMock();
|
|
10
|
+
const account = opts.account ?? createAccountMock();
|
|
11
|
+
const whitelabel = opts.whitelabel ?? createWhitelabelTokenMock();
|
|
12
|
+
return [
|
|
13
|
+
http.get(`${base}/v1/:locale/:wl/whitelabel/:host/token`, () => apiFind(whitelabel)),
|
|
14
|
+
http.get(`${base}/v1/:locale/:wl/tokens`, () => apiFind(whitelabel)),
|
|
15
|
+
// The users path has more segments, so it must come before /accounts/:acc.
|
|
16
|
+
http.get(`${base}/v1/:locale/:wl/accounts/:acc/users/:user`, () => apiFind(user)),
|
|
17
|
+
http.get(`${base}/v1/:locale/:wl/accounts/:acc`, () => apiFind(account))
|
|
18
|
+
];
|
|
19
|
+
}
|
|
20
|
+
export {
|
|
21
|
+
makeSessionHandlers
|
|
22
|
+
};
|
|
23
|
+
//# sourceMappingURL=session.handlers.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/testing/msw/session.handlers.ts"],"sourcesContent":["import { http } from 'msw';\nimport type { Account } from '../../modules/accounts/types';\nimport type { User } from '../../modules/users/schema';\nimport type { WhitelabelTokenData } from '../../modules/whitelabel/schema';\nimport { TEST_API } from '../constants';\nimport { createAccountMock } from '../factories/account.factory';\nimport { createUserMock } from '../factories/user.factory';\nimport { createWhitelabelTokenMock } from '../factories/whitelabel.factory';\nimport { apiFind } from './envelope';\n\nexport interface SessionHandlersOptions {\n // gapps base (= GAPPS_R3_API_URL). Defaults to TEST_API.gapps.\n gappsBase?: string;\n user?: User;\n account?: Account;\n whitelabel?: WhitelabelTokenData;\n}\n\n// Handlers for the server-side session resolution any app triggers when booting an authenticated\n// route (with DUMMY_AUTH_TOKEN): whitelabel by domain, token by wl id, user and account. These are\n// what the layout prefetches and what the ApiClient needs to build the URL/header. Apps compose\n// them with their own handlers:\n// setupServer(...makeSessionHandlers(), ...myPageHandlers)\n// Paths follow the ApiClient template: `{base}/v1/{locale}/{wl}{endpoint}`.\nexport function makeSessionHandlers(opts: SessionHandlersOptions = {}) {\n const base = opts.gappsBase ?? TEST_API.gapps;\n const user = opts.user ?? createUserMock();\n const account = opts.account ?? createAccountMock();\n const whitelabel = opts.whitelabel ?? createWhitelabelTokenMock();\n\n return [\n http.get(`${base}/v1/:locale/:wl/whitelabel/:host/token`, () => apiFind(whitelabel)),\n http.get(`${base}/v1/:locale/:wl/tokens`, () => apiFind(whitelabel)),\n // The users path has more segments, so it must come before /accounts/:acc.\n http.get(`${base}/v1/:locale/:wl/accounts/:acc/users/:user`, () => apiFind(user)),\n http.get(`${base}/v1/:locale/:wl/accounts/:acc`, () => apiFind(account)),\n ];\n}\n"],"mappings":"AAAA,SAAS,YAAY;AAIrB,SAAS,gBAAgB;AACzB,SAAS,yBAAyB;AAClC,SAAS,sBAAsB;AAC/B,SAAS,iCAAiC;AAC1C,SAAS,eAAe;AAgBjB,SAAS,oBAAoB,OAA+B,CAAC,GAAG;AACrE,QAAM,OAAO,KAAK,aAAa,SAAS;AACxC,QAAM,OAAO,KAAK,QAAQ,eAAe;AACzC,QAAM,UAAU,KAAK,WAAW,kBAAkB;AAClD,QAAM,aAAa,KAAK,cAAc,0BAA0B;AAEhE,SAAO;AAAA,IACL,KAAK,IAAI,GAAG,IAAI,0CAA0C,MAAM,QAAQ,UAAU,CAAC;AAAA,IACnF,KAAK,IAAI,GAAG,IAAI,0BAA0B,MAAM,QAAQ,UAAU,CAAC;AAAA;AAAA,IAEnE,KAAK,IAAI,GAAG,IAAI,6CAA6C,MAAM,QAAQ,IAAI,CAAC;AAAA,IAChF,KAAK,IAAI,GAAG,IAAI,iCAAiC,MAAM,QAAQ,OAAO,CAAC;AAAA,EACzE;AACF;","names":[]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/testing/react/index.ts"],"sourcesContent":["export { makeTestQueryClient } from './test-query-client';\nexport { TestProviders, makeProvidersWrapper, type TestProvidersOptions } from './providers';\n"],"mappings":"AAAA,SAAS,2BAA2B;AACpC,SAAS,eAAe,4BAAuD;","names":[]}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { jsx } from "react/jsx-runtime";
|
|
2
|
+
import { QueryClientProvider } from "@tanstack/react-query";
|
|
3
|
+
import { AuthContext } from "../../providers/auth.provider";
|
|
4
|
+
import { WhitelabelProvider } from "../../providers/whitelabel.provider";
|
|
5
|
+
import { createAccountMock } from "../factories/account.factory";
|
|
6
|
+
import { createUserMock } from "../factories/user.factory";
|
|
7
|
+
import { createWhitelabelMock } from "../factories/whitelabel.factory";
|
|
8
|
+
import { makeTestQueryClient } from "./test-query-client";
|
|
9
|
+
const notImpl = async () => {
|
|
10
|
+
throw new Error("auth action is not available in TestProviders \u2014 mock it in the test if needed");
|
|
11
|
+
};
|
|
12
|
+
function TestProviders({
|
|
13
|
+
children,
|
|
14
|
+
...opts
|
|
15
|
+
}) {
|
|
16
|
+
const queryClient = opts.queryClient ?? makeTestQueryClient();
|
|
17
|
+
const user = opts.user === void 0 ? createUserMock() : opts.user;
|
|
18
|
+
const account = opts.account === void 0 ? createAccountMock() : opts.account;
|
|
19
|
+
const whitelabel = opts.whitelabel === void 0 ? createWhitelabelMock() : opts.whitelabel;
|
|
20
|
+
const authValue = {
|
|
21
|
+
user,
|
|
22
|
+
account,
|
|
23
|
+
isAuthenticated: !!user,
|
|
24
|
+
isLoading: false,
|
|
25
|
+
login: notImpl,
|
|
26
|
+
register: notImpl,
|
|
27
|
+
logout: notImpl,
|
|
28
|
+
loginWithGoogle: notImpl,
|
|
29
|
+
completeGoogleOnboarding: notImpl
|
|
30
|
+
};
|
|
31
|
+
return /* @__PURE__ */ jsx(QueryClientProvider, { client: queryClient, children: /* @__PURE__ */ jsx(WhitelabelProvider, { whitelabel, children: /* @__PURE__ */ jsx(AuthContext.Provider, { value: authValue, children }) }) });
|
|
32
|
+
}
|
|
33
|
+
function makeProvidersWrapper(opts = {}) {
|
|
34
|
+
return function ProvidersWrapper({ children }) {
|
|
35
|
+
return /* @__PURE__ */ jsx(TestProviders, { ...opts, children });
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
export {
|
|
39
|
+
TestProviders,
|
|
40
|
+
makeProvidersWrapper
|
|
41
|
+
};
|
|
42
|
+
//# sourceMappingURL=providers.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/testing/react/providers.tsx"],"sourcesContent":["import { QueryClient, QueryClientProvider } from '@tanstack/react-query';\nimport type { ContextType, ReactNode } from 'react';\nimport type { Account } from '../../modules/accounts/types';\nimport type { User } from '../../modules/users/schema';\nimport type { WhitelabelData } from '../../modules/whitelabel/schema';\nimport { AuthContext } from '../../providers/auth.provider';\nimport { WhitelabelProvider } from '../../providers/whitelabel.provider';\nimport { createAccountMock } from '../factories/account.factory';\nimport { createUserMock } from '../factories/user.factory';\nimport { createWhitelabelMock } from '../factories/whitelabel.factory';\nimport { makeTestQueryClient } from './test-query-client';\n\ntype AuthValue = NonNullable<ContextType<typeof AuthContext>>;\n\n// The real AuthProvider runs session queries/actions that don't work in jsdom, so we feed the same\n// (exported) AuthContext a mocked value. The auth actions throw if called — mock them per test.\nconst notImpl = async (): Promise<never> => {\n throw new Error('auth action is not available in TestProviders — mock it in the test if needed');\n};\n\nexport interface TestProvidersOptions {\n queryClient?: QueryClient;\n user?: User | null;\n account?: Account | null;\n whitelabel?: WhitelabelData | null;\n}\n\nexport function TestProviders({\n children,\n ...opts\n}: TestProvidersOptions & { children: ReactNode }) {\n const queryClient = opts.queryClient ?? makeTestQueryClient();\n const user = opts.user === undefined ? createUserMock() : opts.user;\n const account = opts.account === undefined ? createAccountMock() : opts.account;\n const whitelabel = opts.whitelabel === undefined ? createWhitelabelMock() : opts.whitelabel;\n\n const authValue: AuthValue = {\n user,\n account,\n isAuthenticated: !!user,\n isLoading: false,\n login: notImpl,\n register: notImpl,\n logout: notImpl,\n loginWithGoogle: notImpl,\n completeGoogleOnboarding: notImpl,\n };\n\n return (\n <QueryClientProvider client={queryClient}>\n <WhitelabelProvider whitelabel={whitelabel}>\n <AuthContext.Provider value={authValue}>{children}</AuthContext.Provider>\n </WhitelabelProvider>\n </QueryClientProvider>\n );\n}\n\n// Wrapper for Testing Library: `render(ui, { wrapper: makeProvidersWrapper(opts) })`. The\n// @testing-library/react dependency stays in the app, not the common lib, hence a wrapper here\n// rather than a renderWithProviders.\nexport function makeProvidersWrapper(opts: TestProvidersOptions = {}) {\n return function ProvidersWrapper({ children }: { children: ReactNode }) {\n return <TestProviders {...opts}>{children}</TestProviders>;\n };\n}\n"],"mappings":"AAmDQ;AAnDR,SAAsB,2BAA2B;AAKjD,SAAS,mBAAmB;AAC5B,SAAS,0BAA0B;AACnC,SAAS,yBAAyB;AAClC,SAAS,sBAAsB;AAC/B,SAAS,4BAA4B;AACrC,SAAS,2BAA2B;AAMpC,MAAM,UAAU,YAA4B;AAC1C,QAAM,IAAI,MAAM,oFAA+E;AACjG;AASO,SAAS,cAAc;AAAA,EAC5B;AAAA,EACA,GAAG;AACL,GAAmD;AACjD,QAAM,cAAc,KAAK,eAAe,oBAAoB;AAC5D,QAAM,OAAO,KAAK,SAAS,SAAY,eAAe,IAAI,KAAK;AAC/D,QAAM,UAAU,KAAK,YAAY,SAAY,kBAAkB,IAAI,KAAK;AACxE,QAAM,aAAa,KAAK,eAAe,SAAY,qBAAqB,IAAI,KAAK;AAEjF,QAAM,YAAuB;AAAA,IAC3B;AAAA,IACA;AAAA,IACA,iBAAiB,CAAC,CAAC;AAAA,IACnB,WAAW;AAAA,IACX,OAAO;AAAA,IACP,UAAU;AAAA,IACV,QAAQ;AAAA,IACR,iBAAiB;AAAA,IACjB,0BAA0B;AAAA,EAC5B;AAEA,SACE,oBAAC,uBAAoB,QAAQ,aAC3B,8BAAC,sBAAmB,YAClB,8BAAC,YAAY,UAAZ,EAAqB,OAAO,WAAY,UAAS,GACpD,GACF;AAEJ;AAKO,SAAS,qBAAqB,OAA6B,CAAC,GAAG;AACpE,SAAO,SAAS,iBAAiB,EAAE,SAAS,GAA4B;AACtE,WAAO,oBAAC,iBAAe,GAAG,MAAO,UAAS;AAAA,EAC5C;AACF;","names":[]}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { QueryClient } from "@tanstack/react-query";
|
|
2
|
+
function makeTestQueryClient() {
|
|
3
|
+
return new QueryClient({
|
|
4
|
+
defaultOptions: {
|
|
5
|
+
queries: { retry: false, gcTime: 0, staleTime: 0, refetchOnWindowFocus: false },
|
|
6
|
+
mutations: { retry: false }
|
|
7
|
+
}
|
|
8
|
+
});
|
|
9
|
+
}
|
|
10
|
+
export {
|
|
11
|
+
makeTestQueryClient
|
|
12
|
+
};
|
|
13
|
+
//# sourceMappingURL=test-query-client.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/testing/react/test-query-client.ts"],"sourcesContent":["import { QueryClient } from '@tanstack/react-query';\n\n/**\n * QueryClient para testes: sem retry (erros aparecem na hora), sem cache entre testes\n * (`gcTime: 0`) e sem refetch por foco. Crie um por teste pra isolamento total.\n */\nexport function makeTestQueryClient(): QueryClient {\n return new QueryClient({\n defaultOptions: {\n queries: { retry: false, gcTime: 0, staleTime: 0, refetchOnWindowFocus: false },\n mutations: { retry: false },\n },\n });\n}\n"],"mappings":"AAAA,SAAS,mBAAmB;AAMrB,SAAS,sBAAmC;AACjD,SAAO,IAAI,YAAY;AAAA,IACrB,gBAAgB;AAAA,MACd,SAAS,EAAE,OAAO,OAAO,QAAQ,GAAG,WAAW,GAAG,sBAAsB,MAAM;AAAA,MAC9E,WAAW,EAAE,OAAO,MAAM;AAAA,IAC5B;AAAA,EACF,CAAC;AACH;","names":[]}
|
package/dist/testing.mjs
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/testing.ts"],"sourcesContent":["export * from './testing/index';\n"],"mappings":"AAAA,cAAc;","names":[]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@greatapps/common",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.714",
|
|
4
4
|
"description": "Shared library for GreatApps frontend applications",
|
|
5
5
|
"main": "./dist/index.mjs",
|
|
6
6
|
"types": "./src/index.ts",
|
|
@@ -32,6 +32,14 @@
|
|
|
32
32
|
"./i18n": {
|
|
33
33
|
"import": "./dist/i18n.mjs",
|
|
34
34
|
"types": "./src/i18n.ts"
|
|
35
|
+
},
|
|
36
|
+
"./testing": {
|
|
37
|
+
"import": "./dist/testing.mjs",
|
|
38
|
+
"types": "./src/testing.ts"
|
|
39
|
+
},
|
|
40
|
+
"./testing/react": {
|
|
41
|
+
"import": "./dist/testing/react/index.mjs",
|
|
42
|
+
"types": "./src/testing/react/index.ts"
|
|
35
43
|
}
|
|
36
44
|
},
|
|
37
45
|
"files": [
|
|
@@ -89,6 +97,8 @@
|
|
|
89
97
|
"@types/react": "19.2.14",
|
|
90
98
|
"@types/react-dom": "19.2.3",
|
|
91
99
|
"glob": "13.0.6",
|
|
100
|
+
"msw": "2.7.0",
|
|
101
|
+
"@faker-js/faker": "9.9.0",
|
|
92
102
|
"next": "16.2.1",
|
|
93
103
|
"next-intl": "4.12.0",
|
|
94
104
|
"react": "19.1.4",
|
|
@@ -105,11 +115,21 @@
|
|
|
105
115
|
"@tanstack/react-query-persist-client": ">=5.0.0",
|
|
106
116
|
"next": ">=16.0.0",
|
|
107
117
|
"next-intl": ">=4.0.0",
|
|
118
|
+
"@faker-js/faker": ">=9.0.0",
|
|
119
|
+
"msw": ">=2.0.0",
|
|
108
120
|
"react": ">=19.0.0",
|
|
109
121
|
"react-dom": ">=19.0.0",
|
|
110
122
|
"react-hook-form": ">=7.0.0",
|
|
111
123
|
"sonner": ">=2.0.0",
|
|
112
124
|
"zod": ">=4.0.0",
|
|
113
125
|
"zustand": ">=4.0.0"
|
|
126
|
+
},
|
|
127
|
+
"peerDependenciesMeta": {
|
|
128
|
+
"msw": {
|
|
129
|
+
"optional": true
|
|
130
|
+
},
|
|
131
|
+
"@faker-js/faker": {
|
|
132
|
+
"optional": true
|
|
133
|
+
}
|
|
114
134
|
}
|
|
115
135
|
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
// Fixed identity and endpoints used across the test infra. Single source of truth: the same
|
|
2
|
+
// object feeds DUMMY_AUTH_TOKEN (via createTestJwt), the factories and the request handlers, and
|
|
3
|
+
// consumer apps must mirror it in their test env (GAPPS_R3_API_URL etc.) so the URL the ApiClient
|
|
4
|
+
// builds matches the one the handlers expect.
|
|
5
|
+
export const TEST_IDS = {
|
|
6
|
+
wl: 1,
|
|
7
|
+
account: 123,
|
|
8
|
+
user: 456,
|
|
9
|
+
page: 789,
|
|
10
|
+
} as const;
|
|
11
|
+
|
|
12
|
+
// Bases the apps MUST export as test env:
|
|
13
|
+
// GAPPS_R3_API_URL = TEST_API.gapps
|
|
14
|
+
// GPAGES_R3_API_URL = TEST_API.gpages
|
|
15
|
+
// WHITELABEL_TOKEN_MASTER = TEST_API.masterToken
|
|
16
|
+
// WHITELABEL_DOMAIN = TEST_API.domain
|
|
17
|
+
// `.test` domains never resolve on the real network, so a leaked unhandled request fails loudly
|
|
18
|
+
// instead of hitting a real backend.
|
|
19
|
+
export const TEST_API = {
|
|
20
|
+
gapps: 'https://gapps.test',
|
|
21
|
+
gpages: 'https://gpages.test',
|
|
22
|
+
masterToken: 'test-master-token',
|
|
23
|
+
domain: 'app.test',
|
|
24
|
+
} as const;
|
|
25
|
+
|
|
26
|
+
// Fixed locale and version the ApiClient uses to build the URL (`/v1/pt-br/{wl}`).
|
|
27
|
+
export const TEST_API_VERSION = 'v1';
|
|
28
|
+
export const TEST_API_LOCALE = 'pt-br';
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { faker } from '@faker-js/faker';
|
|
2
|
+
import { Account } from '../../modules/accounts/types';
|
|
3
|
+
import { TEST_IDS } from '../constants';
|
|
4
|
+
import { createMock } from './create-mock';
|
|
5
|
+
|
|
6
|
+
// Identity fields (id/id_wl) are fixed to TEST_IDS; cosmetic fields use faker.
|
|
7
|
+
export const createAccountMock = createMock<Account, Partial<Account>>((overrides) => ({
|
|
8
|
+
id: overrides?.id ?? TEST_IDS.account,
|
|
9
|
+
id_wl: overrides?.id_wl ?? TEST_IDS.wl,
|
|
10
|
+
id_affiliate: overrides?.id_affiliate ?? 0,
|
|
11
|
+
id_api: overrides?.id_api ?? 1,
|
|
12
|
+
name: overrides?.name || faker.company.name(),
|
|
13
|
+
language: overrides?.language ?? 'pt-br',
|
|
14
|
+
timezone: overrides?.timezone ?? 'America/Sao_Paulo',
|
|
15
|
+
currency: overrides?.currency ?? 'brl',
|
|
16
|
+
verified: overrides?.verified ?? true,
|
|
17
|
+
bussiness_type: overrides?.bussiness_type ?? 1,
|
|
18
|
+
gateway: overrides?.gateway ?? 'stripe',
|
|
19
|
+
gateway_customer_id: overrides?.gateway_customer_id ?? null,
|
|
20
|
+
origin: overrides?.origin ?? null,
|
|
21
|
+
zipcode: overrides?.zipcode ?? null,
|
|
22
|
+
address: overrides?.address ?? null,
|
|
23
|
+
address_number: overrides?.address_number ?? null,
|
|
24
|
+
address_complement: overrides?.address_complement ?? null,
|
|
25
|
+
neighborhood: overrides?.neighborhood ?? null,
|
|
26
|
+
city: overrides?.city ?? null,
|
|
27
|
+
state: overrides?.state ?? null,
|
|
28
|
+
country: overrides?.country ?? 'BR',
|
|
29
|
+
financial_document: overrides?.financial_document ?? null,
|
|
30
|
+
financial_name: overrides?.financial_name ?? null,
|
|
31
|
+
financial_email: overrides?.financial_email ?? null,
|
|
32
|
+
financial_document_type: overrides?.financial_document_type ?? 1,
|
|
33
|
+
deleted: overrides?.deleted ?? 0,
|
|
34
|
+
datetime_add: overrides?.datetime_add || '2025-01-01 00:00:00',
|
|
35
|
+
datetime_alt: overrides?.datetime_alt || '2025-01-01 00:00:00',
|
|
36
|
+
datetime_del: overrides?.datetime_del ?? null,
|
|
37
|
+
}));
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
type Factory<T, O> = (overrides?: O) => T;
|
|
2
|
+
|
|
3
|
+
// Reset registry for the cached defaults. Runner-agnostic on purpose: these factories also run
|
|
4
|
+
// under `next dev` (E2E request handlers) where vitest's `beforeEach` does not exist, so the app
|
|
5
|
+
// calls `resetMocks()` from its own `beforeEach`.
|
|
6
|
+
const resetters = new Set<() => void>();
|
|
7
|
+
|
|
8
|
+
// createMock(factory) returns a getter that:
|
|
9
|
+
// - without overrides → returns the SAME default instance within a test (stable for asserts);
|
|
10
|
+
// - with overrides → returns a NEW instance with those fields replaced.
|
|
11
|
+
// Between tests, `resetMocks()` refreshes the defaults.
|
|
12
|
+
export function createMock<T, O = Partial<T>>(factory: Factory<T, O>): Factory<T, O> {
|
|
13
|
+
let instance = factory();
|
|
14
|
+
resetters.add(() => {
|
|
15
|
+
instance = factory();
|
|
16
|
+
});
|
|
17
|
+
return (overrides?: O): T => (overrides ? factory(overrides) : instance);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// Refreshes every default cached by createMock. Call it from the setup's beforeEach.
|
|
21
|
+
export function resetMocks(): void {
|
|
22
|
+
for (const reset of resetters) reset();
|
|
23
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export { createMock, resetMocks } from './create-mock';
|
|
2
|
+
export { createTestJwt, type TestJwtClaims } from './jwt';
|
|
3
|
+
export { createUserMock } from './user.factory';
|
|
4
|
+
export { createAccountMock } from './account.factory';
|
|
5
|
+
export { createWhitelabelMock, createWhitelabelTokenMock } from './whitelabel.factory';
|
|
6
|
+
export { createSubscriptionMock, createSubscriptionItemMock } from './subscription.factory';
|
|
7
|
+
export { createPlanMock, createPlanItemMock } from './plan.factory';
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import type { JWTPayload } from '../../modules/users/schema';
|
|
2
|
+
import { TEST_IDS } from '../constants';
|
|
3
|
+
|
|
4
|
+
function b64(value: unknown): string {
|
|
5
|
+
// getUserContext decodes the payload with `atob(token.split('.')[1])`, so standard base64 works.
|
|
6
|
+
return btoa(JSON.stringify(value));
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export interface TestJwtClaims {
|
|
10
|
+
id_wl?: number;
|
|
11
|
+
id_account?: number;
|
|
12
|
+
id_user?: number;
|
|
13
|
+
// Country used by resolveLocale (session.location.country).
|
|
14
|
+
country?: string;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
// Builds a fake JWT (placeholder signature) whose payload is decodable by getUserContext and
|
|
18
|
+
// resolveLocale. Used as DUMMY_AUTH_TOKEN: the common auth bypasses verification when that env is
|
|
19
|
+
// set, so only the payload matters.
|
|
20
|
+
export function createTestJwt(claims: TestJwtClaims = {}): string {
|
|
21
|
+
const payload: JWTPayload = {
|
|
22
|
+
session: {
|
|
23
|
+
location: {
|
|
24
|
+
continent: 'SA',
|
|
25
|
+
country: claims.country ?? 'BR',
|
|
26
|
+
region: 'SP',
|
|
27
|
+
city: 'Sao Paulo',
|
|
28
|
+
latitude: '0',
|
|
29
|
+
longitude: '0',
|
|
30
|
+
},
|
|
31
|
+
ip: '127.0.0.1',
|
|
32
|
+
timezone: 'America/Sao_Paulo',
|
|
33
|
+
agent: 'test',
|
|
34
|
+
code: null,
|
|
35
|
+
},
|
|
36
|
+
id_wl: String(claims.id_wl ?? TEST_IDS.wl),
|
|
37
|
+
id_account: claims.id_account ?? TEST_IDS.account,
|
|
38
|
+
id_user: claims.id_user ?? TEST_IDS.user,
|
|
39
|
+
iss: 'test',
|
|
40
|
+
aud: 'test',
|
|
41
|
+
iat: 1700000000,
|
|
42
|
+
};
|
|
43
|
+
return `${b64({ alg: 'none', typ: 'JWT' })}.${b64(payload)}.sig`;
|
|
44
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { faker } from '@faker-js/faker';
|
|
2
|
+
import { Plan, PlanItem } from '../../modules/plans/types/plan.type';
|
|
3
|
+
import { createMock } from './create-mock';
|
|
4
|
+
|
|
5
|
+
export const createPlanItemMock = createMock<PlanItem, Partial<PlanItem>>((overrides) => ({
|
|
6
|
+
id_addon: overrides?.id_addon ?? 2,
|
|
7
|
+
quantity: overrides?.quantity ?? 10,
|
|
8
|
+
value: overrides?.value ?? 9990,
|
|
9
|
+
base: overrides?.base ?? true,
|
|
10
|
+
}));
|
|
11
|
+
|
|
12
|
+
export const createPlanMock = createMock<Plan, Partial<Plan>>((overrides) => ({
|
|
13
|
+
id: overrides?.id ?? faker.number.int({ min: 1, max: 9999 }),
|
|
14
|
+
name: overrides?.name || faker.commerce.productName(),
|
|
15
|
+
value: overrides?.value ?? 9990,
|
|
16
|
+
currency: overrides?.currency ?? 'brl',
|
|
17
|
+
type: overrides?.type ?? 'paid',
|
|
18
|
+
discount_semester: overrides?.discount_semester ?? 0,
|
|
19
|
+
discount_annual: overrides?.discount_annual ?? 0,
|
|
20
|
+
items: overrides?.items ?? [createPlanItemMock()],
|
|
21
|
+
}));
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { faker } from '@faker-js/faker';
|
|
2
|
+
import { Subscription, SubscriptionItem } from '../../modules/subscriptions/types/subscription.type';
|
|
3
|
+
import { TEST_IDS } from '../constants';
|
|
4
|
+
import { createMock } from './create-mock';
|
|
5
|
+
|
|
6
|
+
// Dates are Date objects (the inferred output of the schema).
|
|
7
|
+
export const createSubscriptionItemMock = createMock<SubscriptionItem, Partial<SubscriptionItem>>(
|
|
8
|
+
(overrides) => ({
|
|
9
|
+
id: overrides?.id ?? faker.number.int({ min: 1, max: 99999 }),
|
|
10
|
+
deleted: overrides?.deleted ?? 0,
|
|
11
|
+
datetime_add: overrides?.datetime_add ?? new Date('2025-01-01T00:00:00Z'),
|
|
12
|
+
id_wl: overrides?.id_wl ?? TEST_IDS.wl,
|
|
13
|
+
id_subscription: overrides?.id_subscription ?? 1,
|
|
14
|
+
id_addon: overrides?.id_addon ?? null,
|
|
15
|
+
value: overrides?.value ?? 9990,
|
|
16
|
+
currency: overrides?.currency ?? 'brl',
|
|
17
|
+
quantity: overrides?.quantity ?? 1,
|
|
18
|
+
payment_status: overrides?.payment_status ?? 1,
|
|
19
|
+
id_charge: overrides?.id_charge ?? null,
|
|
20
|
+
trial: overrides?.trial ?? true,
|
|
21
|
+
}),
|
|
22
|
+
);
|
|
23
|
+
|
|
24
|
+
// Default: an active subscription with a future due date (a valid trial).
|
|
25
|
+
export const createSubscriptionMock = createMock<Subscription, Partial<Subscription>>(
|
|
26
|
+
(overrides) => ({
|
|
27
|
+
id: overrides?.id ?? faker.number.int({ min: 1, max: 99999 }),
|
|
28
|
+
deleted: overrides?.deleted ?? 0,
|
|
29
|
+
datetime_add: overrides?.datetime_add ?? new Date('2025-01-01T00:00:00Z'),
|
|
30
|
+
id_wl: overrides?.id_wl ?? TEST_IDS.wl,
|
|
31
|
+
id_account: overrides?.id_account ?? TEST_IDS.account,
|
|
32
|
+
id_card: overrides?.id_card ?? null,
|
|
33
|
+
id_coupon: overrides?.id_coupon ?? null,
|
|
34
|
+
type: overrides?.type ?? 'recurring',
|
|
35
|
+
payment_method: overrides?.payment_method ?? 1,
|
|
36
|
+
periodicity: overrides?.periodicity ?? 1,
|
|
37
|
+
value: overrides?.value ?? 9990,
|
|
38
|
+
id_product: overrides?.id_product ?? 1,
|
|
39
|
+
id_plan: overrides?.id_plan ?? 1,
|
|
40
|
+
id_gateway: overrides?.id_gateway ?? null,
|
|
41
|
+
gateway_account: overrides?.gateway_account ?? null,
|
|
42
|
+
date_hiring: overrides?.date_hiring ?? new Date('2025-01-01'),
|
|
43
|
+
date_due: overrides?.date_due ?? new Date('2099-01-01'),
|
|
44
|
+
date_cancellation: overrides?.date_cancellation ?? null,
|
|
45
|
+
date_verification: overrides?.date_verification ?? null,
|
|
46
|
+
cancellation_reason: overrides?.cancellation_reason ?? null,
|
|
47
|
+
cancellation_description: overrides?.cancellation_description ?? null,
|
|
48
|
+
active: overrides?.active ?? true,
|
|
49
|
+
charged: overrides?.charged ?? true,
|
|
50
|
+
items: overrides?.items ?? [createSubscriptionItemMock()],
|
|
51
|
+
}),
|
|
52
|
+
);
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { faker } from '@faker-js/faker';
|
|
2
|
+
import { User, UserProfile } from '../../modules/users/schema';
|
|
3
|
+
import { TEST_IDS } from '../constants';
|
|
4
|
+
import { createMock } from './create-mock';
|
|
5
|
+
|
|
6
|
+
// Identity fields (id/id_wl/id_account) are fixed to TEST_IDS by default — the auth chain and the
|
|
7
|
+
// request-URL matching depend on them; override explicitly when needed. Cosmetic fields use faker.
|
|
8
|
+
export const createUserMock = createMock<User, Partial<User>>((overrides) => ({
|
|
9
|
+
id: overrides?.id ?? TEST_IDS.user,
|
|
10
|
+
id_wl: overrides?.id_wl ?? TEST_IDS.wl,
|
|
11
|
+
id_account: overrides?.id_account ?? TEST_IDS.account,
|
|
12
|
+
id_api: overrides?.id_api ?? 1,
|
|
13
|
+
name: overrides?.name || faker.person.firstName(),
|
|
14
|
+
last_name: overrides?.last_name || faker.person.lastName(),
|
|
15
|
+
email: overrides?.email || faker.internet.email().toLowerCase(),
|
|
16
|
+
ddi: overrides?.ddi || '55',
|
|
17
|
+
phone: overrides?.phone || faker.string.numeric(11),
|
|
18
|
+
rg: overrides?.rg ?? null,
|
|
19
|
+
cpf: overrides?.cpf ?? null,
|
|
20
|
+
gender: overrides?.gender ?? 0,
|
|
21
|
+
two_factor_authentication: overrides?.two_factor_authentication ?? false,
|
|
22
|
+
google_sub: overrides?.google_sub ?? null,
|
|
23
|
+
google_linked_at: overrides?.google_linked_at ?? null,
|
|
24
|
+
profile: overrides?.profile ?? UserProfile.owner,
|
|
25
|
+
language: overrides?.language ?? 'pt-br',
|
|
26
|
+
receive_sms: overrides?.receive_sms ?? false,
|
|
27
|
+
receive_email: overrides?.receive_email ?? true,
|
|
28
|
+
photo: overrides?.photo ?? null,
|
|
29
|
+
deleted: overrides?.deleted ?? 0,
|
|
30
|
+
datetime_alt: overrides?.datetime_alt || '2025-01-01 00:00:00',
|
|
31
|
+
datetime_del: overrides?.datetime_del ?? null,
|
|
32
|
+
datetime_add: overrides?.datetime_add || '2025-01-01 00:00:00',
|
|
33
|
+
total_projects: overrides?.total_projects ?? 1,
|
|
34
|
+
projects: overrides?.projects ?? [{ id: 1, title: faker.company.name() }],
|
|
35
|
+
}));
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { faker } from '@faker-js/faker';
|
|
2
|
+
import { WhitelabelData, WhitelabelTokenData } from '../../modules/whitelabel/schema';
|
|
3
|
+
import { TEST_API, TEST_IDS } from '../constants';
|
|
4
|
+
import { createMock } from './create-mock';
|
|
5
|
+
import { createTestJwt } from './jwt';
|
|
6
|
+
|
|
7
|
+
// id/domain stay aligned with TEST_IDS/TEST_API because resolveLocale/branding and the
|
|
8
|
+
// domain-based whitelabel resolution depend on them.
|
|
9
|
+
export const createWhitelabelMock = createMock<WhitelabelData, Partial<WhitelabelData>>(
|
|
10
|
+
(overrides) => {
|
|
11
|
+
const domain = overrides?.domain ?? TEST_API.domain;
|
|
12
|
+
return {
|
|
13
|
+
id: overrides?.id ?? TEST_IDS.wl,
|
|
14
|
+
deleted: overrides?.deleted ?? 0,
|
|
15
|
+
datetime_alt: overrides?.datetime_alt || '2025-01-01 00:00:00',
|
|
16
|
+
datetime_del: overrides?.datetime_del ?? null,
|
|
17
|
+
datetime_add: overrides?.datetime_add || '2025-01-01 00:00:00',
|
|
18
|
+
id_account: overrides?.id_account ?? TEST_IDS.account,
|
|
19
|
+
active: overrides?.active ?? true,
|
|
20
|
+
name: overrides?.name || faker.company.name(),
|
|
21
|
+
email: overrides?.email || faker.internet.email().toLowerCase(),
|
|
22
|
+
email_financial: overrides?.email_financial || faker.internet.email().toLowerCase(),
|
|
23
|
+
email_transactional: overrides?.email_transactional || faker.internet.email().toLowerCase(),
|
|
24
|
+
domain,
|
|
25
|
+
domain_free: overrides?.domain_free ?? null,
|
|
26
|
+
url_help: overrides?.url_help ?? `https://${domain}/help`,
|
|
27
|
+
url_login: overrides?.url_login ?? `https://${domain}/login`,
|
|
28
|
+
url_site: overrides?.url_site ?? `https://${domain}`,
|
|
29
|
+
url_signup: overrides?.url_signup ?? `https://${domain}/signup`,
|
|
30
|
+
codes: overrides?.codes ?? null,
|
|
31
|
+
id_gateway: overrides?.id_gateway ?? 1,
|
|
32
|
+
gateway_product: overrides?.gateway_product ?? 'prod_test',
|
|
33
|
+
external_contracting: overrides?.external_contracting ?? false,
|
|
34
|
+
logo: overrides?.logo ?? `https://${domain}/logo.png`,
|
|
35
|
+
secondary_logo: overrides?.secondary_logo ?? null,
|
|
36
|
+
favicon: overrides?.favicon ?? `https://${domain}/favicon.ico`,
|
|
37
|
+
general: overrides?.general ?? {
|
|
38
|
+
primary_color: faker.color.rgb(),
|
|
39
|
+
hover_color: faker.color.rgb(),
|
|
40
|
+
link_color: faker.color.rgb(),
|
|
41
|
+
},
|
|
42
|
+
signin_page: overrides?.signin_page ?? null,
|
|
43
|
+
signup_page: overrides?.signup_page ?? null,
|
|
44
|
+
dashboard: overrides?.dashboard ?? null,
|
|
45
|
+
use_policy_url: overrides?.use_policy_url ?? `https://${domain}/terms`,
|
|
46
|
+
cookie_policy_url: overrides?.cookie_policy_url ?? `https://${domain}/cookies`,
|
|
47
|
+
privacy_policy_url: overrides?.privacy_policy_url ?? `https://${domain}/privacy`,
|
|
48
|
+
editor_url: overrides?.editor_url ?? `https://editor.${domain}`,
|
|
49
|
+
accounts_url: overrides?.accounts_url ?? `https://accounts.${domain}`,
|
|
50
|
+
pages_url: overrides?.pages_url ?? `https://pages.${domain}`,
|
|
51
|
+
pages_preview_url: overrides?.pages_preview_url ?? `https://preview.${domain}`,
|
|
52
|
+
api_url: overrides?.api_url ?? TEST_API.gpages,
|
|
53
|
+
cname_url: overrides?.cname_url ?? `cname.${domain}`,
|
|
54
|
+
video_url: overrides?.video_url ?? null,
|
|
55
|
+
external_contracting_url: overrides?.external_contracting_url ?? null,
|
|
56
|
+
external_plans_url: overrides?.external_plans_url ?? null,
|
|
57
|
+
};
|
|
58
|
+
},
|
|
59
|
+
);
|
|
60
|
+
|
|
61
|
+
// Variant with `token` — what getTokenByDomain returns for the ApiClient to build the header.
|
|
62
|
+
export const createWhitelabelTokenMock = createMock<WhitelabelTokenData, Partial<WhitelabelTokenData>>(
|
|
63
|
+
(overrides) => ({
|
|
64
|
+
...createWhitelabelMock(overrides),
|
|
65
|
+
token: overrides?.token ?? createTestJwt(),
|
|
66
|
+
}),
|
|
67
|
+
);
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
// Shared test infra for the GreatApps apps. Imported as `@greatapps/common/testing`.
|
|
2
|
+
//
|
|
3
|
+
// This barrel is LIGHT and safe for node/E2E/handlers: only deterministic factories and session
|
|
4
|
+
// request handlers. The React PROVIDERS (which pull the lib's client tree) live in a separate
|
|
5
|
+
// subpath — `@greatapps/common/testing/react` — so the barrel and its load-time side effects
|
|
6
|
+
// (e.g. zustand stores reading localStorage) don't leak into reducer/route-handler tests.
|
|
7
|
+
//
|
|
8
|
+
// `msw` and `@faker-js/faker` are OPTIONAL peer dependencies: only the files here import them.
|
|
9
|
+
export { TEST_IDS, TEST_API, TEST_API_VERSION, TEST_API_LOCALE } from './constants';
|
|
10
|
+
export * from './factories';
|
|
11
|
+
export * from './msw';
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { HttpResponse } from 'msw';
|
|
2
|
+
|
|
3
|
+
// The envelope GreatApps backends return. Services read `data` as an array and take `data[0]` on
|
|
4
|
+
// finds (see the user/account/whitelabel/pages services), so the success default is a list. Use
|
|
5
|
+
// `apiOne` when the consumer expects `data` to be a single object.
|
|
6
|
+
export function apiList<T>(items: T[], total = items.length) {
|
|
7
|
+
return HttpResponse.json({ status: 1, data: items, total });
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
// Success with a single item wrapped in a list (`{ status:1, data:[item], total:1 }`).
|
|
11
|
+
export function apiFind<T>(item: T) {
|
|
12
|
+
return apiList([item], 1);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
// Success with `data` as a single object (few endpoints; most use a list).
|
|
16
|
+
export function apiOne<T>(data: T) {
|
|
17
|
+
return HttpResponse.json({ status: 1, data });
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
// Backend-shaped error (`{ status:0, message }`) with an HTTP status.
|
|
21
|
+
export function apiError(message = 'test error', status = 400) {
|
|
22
|
+
return HttpResponse.json({ status: 0, message }, { status });
|
|
23
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { http } from 'msw';
|
|
2
|
+
import type { Account } from '../../modules/accounts/types';
|
|
3
|
+
import type { User } from '../../modules/users/schema';
|
|
4
|
+
import type { WhitelabelTokenData } from '../../modules/whitelabel/schema';
|
|
5
|
+
import { TEST_API } from '../constants';
|
|
6
|
+
import { createAccountMock } from '../factories/account.factory';
|
|
7
|
+
import { createUserMock } from '../factories/user.factory';
|
|
8
|
+
import { createWhitelabelTokenMock } from '../factories/whitelabel.factory';
|
|
9
|
+
import { apiFind } from './envelope';
|
|
10
|
+
|
|
11
|
+
export interface SessionHandlersOptions {
|
|
12
|
+
// gapps base (= GAPPS_R3_API_URL). Defaults to TEST_API.gapps.
|
|
13
|
+
gappsBase?: string;
|
|
14
|
+
user?: User;
|
|
15
|
+
account?: Account;
|
|
16
|
+
whitelabel?: WhitelabelTokenData;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
// Handlers for the server-side session resolution any app triggers when booting an authenticated
|
|
20
|
+
// route (with DUMMY_AUTH_TOKEN): whitelabel by domain, token by wl id, user and account. These are
|
|
21
|
+
// what the layout prefetches and what the ApiClient needs to build the URL/header. Apps compose
|
|
22
|
+
// them with their own handlers:
|
|
23
|
+
// setupServer(...makeSessionHandlers(), ...myPageHandlers)
|
|
24
|
+
// Paths follow the ApiClient template: `{base}/v1/{locale}/{wl}{endpoint}`.
|
|
25
|
+
export function makeSessionHandlers(opts: SessionHandlersOptions = {}) {
|
|
26
|
+
const base = opts.gappsBase ?? TEST_API.gapps;
|
|
27
|
+
const user = opts.user ?? createUserMock();
|
|
28
|
+
const account = opts.account ?? createAccountMock();
|
|
29
|
+
const whitelabel = opts.whitelabel ?? createWhitelabelTokenMock();
|
|
30
|
+
|
|
31
|
+
return [
|
|
32
|
+
http.get(`${base}/v1/:locale/:wl/whitelabel/:host/token`, () => apiFind(whitelabel)),
|
|
33
|
+
http.get(`${base}/v1/:locale/:wl/tokens`, () => apiFind(whitelabel)),
|
|
34
|
+
// The users path has more segments, so it must come before /accounts/:acc.
|
|
35
|
+
http.get(`${base}/v1/:locale/:wl/accounts/:acc/users/:user`, () => apiFind(user)),
|
|
36
|
+
http.get(`${base}/v1/:locale/:wl/accounts/:acc`, () => apiFind(account)),
|
|
37
|
+
];
|
|
38
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
|
|
2
|
+
import type { ContextType, ReactNode } from 'react';
|
|
3
|
+
import type { Account } from '../../modules/accounts/types';
|
|
4
|
+
import type { User } from '../../modules/users/schema';
|
|
5
|
+
import type { WhitelabelData } from '../../modules/whitelabel/schema';
|
|
6
|
+
import { AuthContext } from '../../providers/auth.provider';
|
|
7
|
+
import { WhitelabelProvider } from '../../providers/whitelabel.provider';
|
|
8
|
+
import { createAccountMock } from '../factories/account.factory';
|
|
9
|
+
import { createUserMock } from '../factories/user.factory';
|
|
10
|
+
import { createWhitelabelMock } from '../factories/whitelabel.factory';
|
|
11
|
+
import { makeTestQueryClient } from './test-query-client';
|
|
12
|
+
|
|
13
|
+
type AuthValue = NonNullable<ContextType<typeof AuthContext>>;
|
|
14
|
+
|
|
15
|
+
// The real AuthProvider runs session queries/actions that don't work in jsdom, so we feed the same
|
|
16
|
+
// (exported) AuthContext a mocked value. The auth actions throw if called — mock them per test.
|
|
17
|
+
const notImpl = async (): Promise<never> => {
|
|
18
|
+
throw new Error('auth action is not available in TestProviders — mock it in the test if needed');
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
export interface TestProvidersOptions {
|
|
22
|
+
queryClient?: QueryClient;
|
|
23
|
+
user?: User | null;
|
|
24
|
+
account?: Account | null;
|
|
25
|
+
whitelabel?: WhitelabelData | null;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export function TestProviders({
|
|
29
|
+
children,
|
|
30
|
+
...opts
|
|
31
|
+
}: TestProvidersOptions & { children: ReactNode }) {
|
|
32
|
+
const queryClient = opts.queryClient ?? makeTestQueryClient();
|
|
33
|
+
const user = opts.user === undefined ? createUserMock() : opts.user;
|
|
34
|
+
const account = opts.account === undefined ? createAccountMock() : opts.account;
|
|
35
|
+
const whitelabel = opts.whitelabel === undefined ? createWhitelabelMock() : opts.whitelabel;
|
|
36
|
+
|
|
37
|
+
const authValue: AuthValue = {
|
|
38
|
+
user,
|
|
39
|
+
account,
|
|
40
|
+
isAuthenticated: !!user,
|
|
41
|
+
isLoading: false,
|
|
42
|
+
login: notImpl,
|
|
43
|
+
register: notImpl,
|
|
44
|
+
logout: notImpl,
|
|
45
|
+
loginWithGoogle: notImpl,
|
|
46
|
+
completeGoogleOnboarding: notImpl,
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
return (
|
|
50
|
+
<QueryClientProvider client={queryClient}>
|
|
51
|
+
<WhitelabelProvider whitelabel={whitelabel}>
|
|
52
|
+
<AuthContext.Provider value={authValue}>{children}</AuthContext.Provider>
|
|
53
|
+
</WhitelabelProvider>
|
|
54
|
+
</QueryClientProvider>
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// Wrapper for Testing Library: `render(ui, { wrapper: makeProvidersWrapper(opts) })`. The
|
|
59
|
+
// @testing-library/react dependency stays in the app, not the common lib, hence a wrapper here
|
|
60
|
+
// rather than a renderWithProviders.
|
|
61
|
+
export function makeProvidersWrapper(opts: TestProvidersOptions = {}) {
|
|
62
|
+
return function ProvidersWrapper({ children }: { children: ReactNode }) {
|
|
63
|
+
return <TestProviders {...opts}>{children}</TestProviders>;
|
|
64
|
+
};
|
|
65
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { QueryClient } from '@tanstack/react-query';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* QueryClient para testes: sem retry (erros aparecem na hora), sem cache entre testes
|
|
5
|
+
* (`gcTime: 0`) e sem refetch por foco. Crie um por teste pra isolamento total.
|
|
6
|
+
*/
|
|
7
|
+
export function makeTestQueryClient(): QueryClient {
|
|
8
|
+
return new QueryClient({
|
|
9
|
+
defaultOptions: {
|
|
10
|
+
queries: { retry: false, gcTime: 0, staleTime: 0, refetchOnWindowFocus: false },
|
|
11
|
+
mutations: { retry: false },
|
|
12
|
+
},
|
|
13
|
+
});
|
|
14
|
+
}
|
package/src/testing.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './testing/index';
|