@open-mercato/enterprise 0.4.5-develop-2e9903a57a → 0.4.5-develop-eeccf7adf4
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/package.json +4 -4
- package/dist/modules/record_locks/__integration__/TC-LOCK-001.spec.js +0 -73
- package/dist/modules/record_locks/__integration__/TC-LOCK-001.spec.js.map +0 -7
- package/dist/modules/record_locks/__integration__/TC-LOCK-002.spec.js +0 -114
- package/dist/modules/record_locks/__integration__/TC-LOCK-002.spec.js.map +0 -7
- package/dist/modules/record_locks/__integration__/TC-LOCK-003.spec.js +0 -119
- package/dist/modules/record_locks/__integration__/TC-LOCK-003.spec.js.map +0 -7
- package/dist/modules/record_locks/__integration__/TC-LOCK-004.spec.js +0 -119
- package/dist/modules/record_locks/__integration__/TC-LOCK-004.spec.js.map +0 -7
- package/dist/modules/record_locks/__integration__/TC-LOCK-005.spec.js +0 -90
- package/dist/modules/record_locks/__integration__/TC-LOCK-005.spec.js.map +0 -7
- package/dist/modules/record_locks/__integration__/TC-LOCK-006.spec.js +0 -90
- package/dist/modules/record_locks/__integration__/TC-LOCK-006.spec.js.map +0 -7
- package/dist/modules/record_locks/__integration__/TC-LOCK-007.spec.js +0 -211
- package/dist/modules/record_locks/__integration__/TC-LOCK-007.spec.js.map +0 -7
- package/dist/modules/record_locks/__integration__/helpers/recordLocks.js +0 -219
- package/dist/modules/record_locks/__integration__/helpers/recordLocks.js.map +0 -7
- package/src/modules/record_locks/__integration__/TC-LOCK-001.spec.ts +0 -84
- package/src/modules/record_locks/__integration__/TC-LOCK-002.spec.ts +0 -129
- package/src/modules/record_locks/__integration__/TC-LOCK-003.spec.ts +0 -136
- package/src/modules/record_locks/__integration__/TC-LOCK-004.spec.ts +0 -136
- package/src/modules/record_locks/__integration__/TC-LOCK-005.spec.ts +0 -106
- package/src/modules/record_locks/__integration__/TC-LOCK-006.spec.ts +0 -113
- package/src/modules/record_locks/__integration__/TC-LOCK-007.spec.ts +0 -251
- package/src/modules/record_locks/__integration__/helpers/recordLocks.ts +0 -366
- package/src/modules/record_locks/__tests__/config.test.ts +0 -21
- package/src/modules/record_locks/__tests__/crudMutationGuardService.test.ts +0 -106
- package/src/modules/record_locks/__tests__/recordLockService.test.ts +0 -1226
- package/src/modules/record_locks/__tests__/recordLockWidgetHeaders.test.ts +0 -127
- package/src/modules/record_locks/api/__tests__/acquire.route.test.ts +0 -175
- package/src/modules/record_locks/api/__tests__/release.route.test.ts +0 -135
- package/src/modules/record_locks/api/__tests__/settings.route.test.ts +0 -85
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@open-mercato/enterprise",
|
|
3
|
-
"version": "0.4.5-develop-
|
|
3
|
+
"version": "0.4.5-develop-eeccf7adf4",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -64,9 +64,9 @@
|
|
|
64
64
|
}
|
|
65
65
|
},
|
|
66
66
|
"dependencies": {
|
|
67
|
-
"@open-mercato/core": "0.4.5-develop-
|
|
68
|
-
"@open-mercato/shared": "0.4.5-develop-
|
|
69
|
-
"@open-mercato/ui": "0.4.5-develop-
|
|
67
|
+
"@open-mercato/core": "0.4.5-develop-eeccf7adf4",
|
|
68
|
+
"@open-mercato/shared": "0.4.5-develop-eeccf7adf4",
|
|
69
|
+
"@open-mercato/ui": "0.4.5-develop-eeccf7adf4"
|
|
70
70
|
},
|
|
71
71
|
"devDependencies": {
|
|
72
72
|
"@types/jest": "^30.0.0",
|
|
@@ -1,73 +0,0 @@
|
|
|
1
|
-
import { expect, test } from "@playwright/test";
|
|
2
|
-
import { getAuthToken } from "@open-mercato/core/modules/core/__integration__/helpers/api";
|
|
3
|
-
import { createCompanyFixture } from "@open-mercato/core/modules/core/__integration__/helpers/crmFixtures";
|
|
4
|
-
import {
|
|
5
|
-
acquireRecordLock,
|
|
6
|
-
cleanupCompany,
|
|
7
|
-
getRecordLockSettings,
|
|
8
|
-
releaseRecordLock,
|
|
9
|
-
saveRecordLockSettings,
|
|
10
|
-
updateCompany
|
|
11
|
-
} from "./helpers/recordLocks.js";
|
|
12
|
-
test.describe("TC-LOCK-001: Pessimistic lock blocks a second editor", () => {
|
|
13
|
-
test.describe.configure({ timeout: 9e4 });
|
|
14
|
-
test("should return 423 for secondary editor update while lock is active", async ({ request }) => {
|
|
15
|
-
const superadminToken = await getAuthToken(request, "superadmin");
|
|
16
|
-
const adminToken = await getAuthToken(request, "admin");
|
|
17
|
-
let previousSettings = null;
|
|
18
|
-
let companyId = null;
|
|
19
|
-
let ownerLockToken = null;
|
|
20
|
-
try {
|
|
21
|
-
previousSettings = await getRecordLockSettings(request, superadminToken);
|
|
22
|
-
await saveRecordLockSettings(request, superadminToken, {
|
|
23
|
-
...previousSettings,
|
|
24
|
-
enabled: true,
|
|
25
|
-
strategy: "pessimistic",
|
|
26
|
-
enabledResources: ["customers.company"]
|
|
27
|
-
});
|
|
28
|
-
companyId = await createCompanyFixture(request, adminToken, `QA TC-LOCK-001 Company ${Date.now()}`);
|
|
29
|
-
const ownerAcquire = await acquireRecordLock(request, superadminToken, "customers.company", companyId);
|
|
30
|
-
expect(ownerAcquire.status).toBe(200);
|
|
31
|
-
expect(ownerAcquire.body?.ok).toBe(true);
|
|
32
|
-
ownerLockToken = ownerAcquire.body?.lock?.token ?? null;
|
|
33
|
-
expect(ownerLockToken).toBeTruthy();
|
|
34
|
-
const blockedUpdate = await updateCompany(
|
|
35
|
-
request,
|
|
36
|
-
adminToken,
|
|
37
|
-
companyId,
|
|
38
|
-
`QA TC-LOCK-001 Blocked Update ${Date.now()}`
|
|
39
|
-
);
|
|
40
|
-
expect(blockedUpdate.status).toBe(423);
|
|
41
|
-
expect(blockedUpdate.body?.code).toBe("record_locked");
|
|
42
|
-
const ownerRelease = await releaseRecordLock(
|
|
43
|
-
request,
|
|
44
|
-
superadminToken,
|
|
45
|
-
"customers.company",
|
|
46
|
-
companyId,
|
|
47
|
-
ownerLockToken
|
|
48
|
-
);
|
|
49
|
-
expect(ownerRelease.status).toBe(200);
|
|
50
|
-
expect(ownerRelease.body?.released).toBe(true);
|
|
51
|
-
ownerLockToken = null;
|
|
52
|
-
const updateAfterRelease = await updateCompany(
|
|
53
|
-
request,
|
|
54
|
-
adminToken,
|
|
55
|
-
companyId,
|
|
56
|
-
`QA TC-LOCK-001 Unblocked Update ${Date.now()}`
|
|
57
|
-
);
|
|
58
|
-
expect(updateAfterRelease.status).toBe(200);
|
|
59
|
-
expect(updateAfterRelease.body?.ok).toBe(true);
|
|
60
|
-
} finally {
|
|
61
|
-
if (ownerLockToken && companyId) {
|
|
62
|
-
await releaseRecordLock(request, superadminToken, "customers.company", companyId, ownerLockToken).catch(() => {
|
|
63
|
-
});
|
|
64
|
-
}
|
|
65
|
-
await cleanupCompany(request, adminToken, companyId);
|
|
66
|
-
if (previousSettings) {
|
|
67
|
-
await saveRecordLockSettings(request, superadminToken, previousSettings).catch(() => {
|
|
68
|
-
});
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
});
|
|
72
|
-
});
|
|
73
|
-
//# sourceMappingURL=TC-LOCK-001.spec.js.map
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../../../../src/modules/record_locks/__integration__/TC-LOCK-001.spec.ts"],
|
|
4
|
-
"sourcesContent": ["import { expect, test } from '@playwright/test';\nimport { getAuthToken } from '@open-mercato/core/modules/core/__integration__/helpers/api';\nimport { createCompanyFixture } from '@open-mercato/core/modules/core/__integration__/helpers/crmFixtures';\nimport {\n acquireRecordLock,\n cleanupCompany,\n getRecordLockSettings,\n releaseRecordLock,\n saveRecordLockSettings,\n updateCompany,\n type RecordLockSettings,\n} from './helpers/recordLocks';\n\n/**\n * TC-LOCK-001: Pessimistic lock blocks a second editor\n */\ntest.describe('TC-LOCK-001: Pessimistic lock blocks a second editor', () => {\n test.describe.configure({ timeout: 90_000 });\n\n test('should return 423 for secondary editor update while lock is active', async ({ request }) => {\n const superadminToken = await getAuthToken(request, 'superadmin');\n const adminToken = await getAuthToken(request, 'admin');\n\n let previousSettings: RecordLockSettings | null = null;\n let companyId: string | null = null;\n let ownerLockToken: string | null = null;\n\n try {\n previousSettings = await getRecordLockSettings(request, superadminToken);\n await saveRecordLockSettings(request, superadminToken, {\n ...previousSettings,\n enabled: true,\n strategy: 'pessimistic',\n enabledResources: ['customers.company'],\n });\n\n companyId = await createCompanyFixture(request, adminToken, `QA TC-LOCK-001 Company ${Date.now()}`);\n\n const ownerAcquire = await acquireRecordLock(request, superadminToken, 'customers.company', companyId);\n expect(ownerAcquire.status).toBe(200);\n expect(ownerAcquire.body?.ok).toBe(true);\n ownerLockToken =\n (ownerAcquire.body?.lock as { token?: string | null } | undefined)?.token ?? null;\n expect(ownerLockToken).toBeTruthy();\n\n const blockedUpdate = await updateCompany(\n request,\n adminToken,\n companyId,\n `QA TC-LOCK-001 Blocked Update ${Date.now()}`,\n );\n expect(blockedUpdate.status).toBe(423);\n expect(blockedUpdate.body?.code).toBe('record_locked');\n\n const ownerRelease = await releaseRecordLock(\n request,\n superadminToken,\n 'customers.company',\n companyId,\n ownerLockToken as string,\n );\n expect(ownerRelease.status).toBe(200);\n expect(ownerRelease.body?.released).toBe(true);\n ownerLockToken = null;\n\n const updateAfterRelease = await updateCompany(\n request,\n adminToken,\n companyId,\n `QA TC-LOCK-001 Unblocked Update ${Date.now()}`,\n );\n expect(updateAfterRelease.status).toBe(200);\n expect(updateAfterRelease.body?.ok).toBe(true);\n } finally {\n if (ownerLockToken && companyId) {\n await releaseRecordLock(request, superadminToken, 'customers.company', companyId, ownerLockToken).catch(() => {});\n }\n await cleanupCompany(request, adminToken, companyId);\n if (previousSettings) {\n await saveRecordLockSettings(request, superadminToken, previousSettings).catch(() => {});\n }\n }\n });\n});\n"],
|
|
5
|
-
"mappings": "AAAA,SAAS,QAAQ,YAAY;AAC7B,SAAS,oBAAoB;AAC7B,SAAS,4BAA4B;AACrC;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OAEK;AAKP,KAAK,SAAS,wDAAwD,MAAM;AAC1E,OAAK,SAAS,UAAU,EAAE,SAAS,IAAO,CAAC;AAE3C,OAAK,sEAAsE,OAAO,EAAE,QAAQ,MAAM;AAChG,UAAM,kBAAkB,MAAM,aAAa,SAAS,YAAY;AAChE,UAAM,aAAa,MAAM,aAAa,SAAS,OAAO;AAEtD,QAAI,mBAA8C;AAClD,QAAI,YAA2B;AAC/B,QAAI,iBAAgC;AAEpC,QAAI;AACF,yBAAmB,MAAM,sBAAsB,SAAS,eAAe;AACvE,YAAM,uBAAuB,SAAS,iBAAiB;AAAA,QACrD,GAAG;AAAA,QACH,SAAS;AAAA,QACT,UAAU;AAAA,QACV,kBAAkB,CAAC,mBAAmB;AAAA,MACxC,CAAC;AAED,kBAAY,MAAM,qBAAqB,SAAS,YAAY,0BAA0B,KAAK,IAAI,CAAC,EAAE;AAElG,YAAM,eAAe,MAAM,kBAAkB,SAAS,iBAAiB,qBAAqB,SAAS;AACrG,aAAO,aAAa,MAAM,EAAE,KAAK,GAAG;AACpC,aAAO,aAAa,MAAM,EAAE,EAAE,KAAK,IAAI;AACvC,uBACG,aAAa,MAAM,MAAgD,SAAS;AAC/E,aAAO,cAAc,EAAE,WAAW;AAElC,YAAM,gBAAgB,MAAM;AAAA,QAC1B;AAAA,QACA;AAAA,QACA;AAAA,QACA,iCAAiC,KAAK,IAAI,CAAC;AAAA,MAC7C;AACA,aAAO,cAAc,MAAM,EAAE,KAAK,GAAG;AACrC,aAAO,cAAc,MAAM,IAAI,EAAE,KAAK,eAAe;AAErD,YAAM,eAAe,MAAM;AAAA,QACzB;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF;AACA,aAAO,aAAa,MAAM,EAAE,KAAK,GAAG;AACpC,aAAO,aAAa,MAAM,QAAQ,EAAE,KAAK,IAAI;AAC7C,uBAAiB;AAEjB,YAAM,qBAAqB,MAAM;AAAA,QAC/B;AAAA,QACA;AAAA,QACA;AAAA,QACA,mCAAmC,KAAK,IAAI,CAAC;AAAA,MAC/C;AACA,aAAO,mBAAmB,MAAM,EAAE,KAAK,GAAG;AAC1C,aAAO,mBAAmB,MAAM,EAAE,EAAE,KAAK,IAAI;AAAA,IAC/C,UAAE;AACA,UAAI,kBAAkB,WAAW;AAC/B,cAAM,kBAAkB,SAAS,iBAAiB,qBAAqB,WAAW,cAAc,EAAE,MAAM,MAAM;AAAA,QAAC,CAAC;AAAA,MAClH;AACA,YAAM,eAAe,SAAS,YAAY,SAAS;AACnD,UAAI,kBAAkB;AACpB,cAAM,uBAAuB,SAAS,iBAAiB,gBAAgB,EAAE,MAAM,MAAM;AAAA,QAAC,CAAC;AAAA,MACzF;AAAA,IACF;AAAA,EACF,CAAC;AACH,CAAC;",
|
|
6
|
-
"names": []
|
|
7
|
-
}
|
|
@@ -1,114 +0,0 @@
|
|
|
1
|
-
import { expect, test } from "@playwright/test";
|
|
2
|
-
import { getAuthToken } from "@open-mercato/core/modules/core/__integration__/helpers/api";
|
|
3
|
-
import { createCompanyFixture } from "@open-mercato/core/modules/core/__integration__/helpers/crmFixtures";
|
|
4
|
-
import {
|
|
5
|
-
acquireRecordLock,
|
|
6
|
-
cleanupCompany,
|
|
7
|
-
buildScopeCookieFromToken,
|
|
8
|
-
getCompanyDisplayName,
|
|
9
|
-
getRecordLockSettings,
|
|
10
|
-
releaseRecordLock,
|
|
11
|
-
saveRecordLockSettings,
|
|
12
|
-
updateCompany,
|
|
13
|
-
waitForNotification
|
|
14
|
-
} from "./helpers/recordLocks.js";
|
|
15
|
-
test.describe("TC-LOCK-002: Optimistic conflict with accept incoming path", () => {
|
|
16
|
-
test.describe.configure({ timeout: 9e4 });
|
|
17
|
-
test("should keep incoming change when conflicted editor accepts incoming", async ({ request }) => {
|
|
18
|
-
const superadminToken = await getAuthToken(request, "superadmin");
|
|
19
|
-
const adminToken = await getAuthToken(request, "admin");
|
|
20
|
-
const superadminScopeCookie = buildScopeCookieFromToken(superadminToken);
|
|
21
|
-
const superadminScopeHeaders = superadminScopeCookie ? { cookie: superadminScopeCookie } : void 0;
|
|
22
|
-
let previousSettings = null;
|
|
23
|
-
let companyId = null;
|
|
24
|
-
let ownerLockToken = null;
|
|
25
|
-
try {
|
|
26
|
-
previousSettings = await getRecordLockSettings(request, superadminToken);
|
|
27
|
-
await saveRecordLockSettings(request, superadminToken, {
|
|
28
|
-
...previousSettings,
|
|
29
|
-
enabled: true,
|
|
30
|
-
strategy: "optimistic",
|
|
31
|
-
enabledResources: ["customers.company"],
|
|
32
|
-
notifyOnConflict: true
|
|
33
|
-
});
|
|
34
|
-
companyId = await createCompanyFixture(request, adminToken, `QA TC-LOCK-002 Company ${Date.now()}`);
|
|
35
|
-
const acquire = await acquireRecordLock(
|
|
36
|
-
request,
|
|
37
|
-
superadminToken,
|
|
38
|
-
"customers.company",
|
|
39
|
-
companyId,
|
|
40
|
-
superadminScopeHeaders
|
|
41
|
-
);
|
|
42
|
-
expect(acquire.status).toBe(200);
|
|
43
|
-
ownerLockToken = acquire.body?.lock?.token ?? null;
|
|
44
|
-
const baseLogId = acquire.body?.latestActionLogId ?? null;
|
|
45
|
-
expect(ownerLockToken).toBeTruthy();
|
|
46
|
-
expect(baseLogId).toBeTruthy();
|
|
47
|
-
const incomingName = `QA TC-LOCK-002 Incoming ${Date.now()}`;
|
|
48
|
-
const incomingUpdate = await updateCompany(request, adminToken, companyId, incomingName);
|
|
49
|
-
expect(incomingUpdate.status).toBe(200);
|
|
50
|
-
const staleUpdate = await updateCompany(
|
|
51
|
-
request,
|
|
52
|
-
superadminToken,
|
|
53
|
-
companyId,
|
|
54
|
-
`QA TC-LOCK-002 Mine ${Date.now()}`,
|
|
55
|
-
{
|
|
56
|
-
token: ownerLockToken,
|
|
57
|
-
baseLogId,
|
|
58
|
-
resolution: "normal"
|
|
59
|
-
},
|
|
60
|
-
superadminScopeHeaders
|
|
61
|
-
);
|
|
62
|
-
expect(staleUpdate.status).toBe(409);
|
|
63
|
-
expect(staleUpdate.body?.code).toBe("record_lock_conflict");
|
|
64
|
-
const conflictId = staleUpdate.body?.conflict?.id ?? null;
|
|
65
|
-
expect(conflictId).toBeTruthy();
|
|
66
|
-
const releaseResult = await releaseRecordLock(
|
|
67
|
-
request,
|
|
68
|
-
superadminToken,
|
|
69
|
-
"customers.company",
|
|
70
|
-
companyId,
|
|
71
|
-
ownerLockToken,
|
|
72
|
-
"conflict_resolved",
|
|
73
|
-
{
|
|
74
|
-
conflictId,
|
|
75
|
-
resolution: "accept_incoming"
|
|
76
|
-
},
|
|
77
|
-
superadminScopeHeaders
|
|
78
|
-
);
|
|
79
|
-
expect(releaseResult.status).toBe(200);
|
|
80
|
-
expect(releaseResult.body?.released).toBe(true);
|
|
81
|
-
expect(releaseResult.body?.conflictResolved).toBe(true);
|
|
82
|
-
ownerLockToken = null;
|
|
83
|
-
const finalName = await getCompanyDisplayName(request, adminToken, companyId);
|
|
84
|
-
expect(finalName).toBe(incomingName);
|
|
85
|
-
const resolvedNotification = await waitForNotification(
|
|
86
|
-
request,
|
|
87
|
-
adminToken,
|
|
88
|
-
"record_locks.conflict.resolved",
|
|
89
|
-
(item) => item.sourceEntityId === conflictId
|
|
90
|
-
);
|
|
91
|
-
expect(resolvedNotification.bodyVariables?.resolution).toBe("accept_incoming");
|
|
92
|
-
} finally {
|
|
93
|
-
if (ownerLockToken && companyId) {
|
|
94
|
-
await releaseRecordLock(
|
|
95
|
-
request,
|
|
96
|
-
superadminToken,
|
|
97
|
-
"customers.company",
|
|
98
|
-
companyId,
|
|
99
|
-
ownerLockToken,
|
|
100
|
-
"cancelled",
|
|
101
|
-
void 0,
|
|
102
|
-
superadminScopeHeaders
|
|
103
|
-
).catch(() => {
|
|
104
|
-
});
|
|
105
|
-
}
|
|
106
|
-
await cleanupCompany(request, adminToken, companyId);
|
|
107
|
-
if (previousSettings) {
|
|
108
|
-
await saveRecordLockSettings(request, superadminToken, previousSettings).catch(() => {
|
|
109
|
-
});
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
});
|
|
113
|
-
});
|
|
114
|
-
//# sourceMappingURL=TC-LOCK-002.spec.js.map
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../../../../src/modules/record_locks/__integration__/TC-LOCK-002.spec.ts"],
|
|
4
|
-
"sourcesContent": ["import { expect, test } from '@playwright/test';\nimport { getAuthToken } from '@open-mercato/core/modules/core/__integration__/helpers/api';\nimport { createCompanyFixture } from '@open-mercato/core/modules/core/__integration__/helpers/crmFixtures';\nimport {\n acquireRecordLock,\n cleanupCompany,\n buildScopeCookieFromToken,\n getCompanyDisplayName,\n getRecordLockSettings,\n releaseRecordLock,\n saveRecordLockSettings,\n updateCompany,\n waitForNotification,\n type RecordLockSettings,\n} from './helpers/recordLocks';\n\n/**\n * TC-LOCK-002: Optimistic conflict with accept incoming path\n */\ntest.describe('TC-LOCK-002: Optimistic conflict with accept incoming path', () => {\n test.describe.configure({ timeout: 90_000 });\n\n test('should keep incoming change when conflicted editor accepts incoming', async ({ request }) => {\n const superadminToken = await getAuthToken(request, 'superadmin');\n const adminToken = await getAuthToken(request, 'admin');\n const superadminScopeCookie = buildScopeCookieFromToken(superadminToken);\n const superadminScopeHeaders = superadminScopeCookie ? { cookie: superadminScopeCookie } : undefined;\n\n let previousSettings: RecordLockSettings | null = null;\n let companyId: string | null = null;\n let ownerLockToken: string | null = null;\n\n try {\n previousSettings = await getRecordLockSettings(request, superadminToken);\n await saveRecordLockSettings(request, superadminToken, {\n ...previousSettings,\n enabled: true,\n strategy: 'optimistic',\n enabledResources: ['customers.company'],\n notifyOnConflict: true,\n });\n\n companyId = await createCompanyFixture(request, adminToken, `QA TC-LOCK-002 Company ${Date.now()}`);\n\n const acquire = await acquireRecordLock(\n request,\n superadminToken,\n 'customers.company',\n companyId,\n superadminScopeHeaders,\n );\n expect(acquire.status).toBe(200);\n ownerLockToken = (acquire.body?.lock as { token?: string | null } | undefined)?.token ?? null;\n const baseLogId =\n (acquire.body as { latestActionLogId?: string | null } | null)?.latestActionLogId ?? null;\n expect(ownerLockToken).toBeTruthy();\n expect(baseLogId).toBeTruthy();\n\n const incomingName = `QA TC-LOCK-002 Incoming ${Date.now()}`;\n const incomingUpdate = await updateCompany(request, adminToken, companyId, incomingName);\n expect(incomingUpdate.status).toBe(200);\n\n const staleUpdate = await updateCompany(\n request,\n superadminToken,\n companyId,\n `QA TC-LOCK-002 Mine ${Date.now()}`,\n {\n token: ownerLockToken,\n baseLogId,\n resolution: 'normal',\n },\n superadminScopeHeaders,\n );\n\n expect(staleUpdate.status).toBe(409);\n expect(staleUpdate.body?.code).toBe('record_lock_conflict');\n const conflictId =\n (staleUpdate.body?.conflict as { id?: string } | undefined)?.id ?? null;\n expect(conflictId).toBeTruthy();\n\n const releaseResult = await releaseRecordLock(\n request,\n superadminToken,\n 'customers.company',\n companyId,\n ownerLockToken as string,\n 'conflict_resolved',\n {\n conflictId,\n resolution: 'accept_incoming',\n },\n superadminScopeHeaders,\n );\n expect(releaseResult.status).toBe(200);\n expect(releaseResult.body?.released).toBe(true);\n expect(releaseResult.body?.conflictResolved).toBe(true);\n ownerLockToken = null;\n\n const finalName = await getCompanyDisplayName(request, adminToken, companyId);\n expect(finalName).toBe(incomingName);\n\n const resolvedNotification = await waitForNotification(\n request,\n adminToken,\n 'record_locks.conflict.resolved',\n (item) => item.sourceEntityId === conflictId,\n );\n expect(resolvedNotification.bodyVariables?.resolution).toBe('accept_incoming');\n } finally {\n if (ownerLockToken && companyId) {\n await releaseRecordLock(\n request,\n superadminToken,\n 'customers.company',\n companyId,\n ownerLockToken,\n 'cancelled',\n undefined,\n superadminScopeHeaders,\n ).catch(() => {});\n }\n await cleanupCompany(request, adminToken, companyId);\n if (previousSettings) {\n await saveRecordLockSettings(request, superadminToken, previousSettings).catch(() => {});\n }\n }\n });\n});\n"],
|
|
5
|
-
"mappings": "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",
|
|
6
|
-
"names": []
|
|
7
|
-
}
|
|
@@ -1,119 +0,0 @@
|
|
|
1
|
-
import { expect, test } from "@playwright/test";
|
|
2
|
-
import { getAuthToken } from "@open-mercato/core/modules/core/__integration__/helpers/api";
|
|
3
|
-
import { createCompanyFixture } from "@open-mercato/core/modules/core/__integration__/helpers/crmFixtures";
|
|
4
|
-
import {
|
|
5
|
-
acquireRecordLock,
|
|
6
|
-
cleanupCompany,
|
|
7
|
-
buildScopeCookieFromToken,
|
|
8
|
-
getCompanyDisplayName,
|
|
9
|
-
getRecordLockSettings,
|
|
10
|
-
releaseRecordLock,
|
|
11
|
-
saveRecordLockSettings,
|
|
12
|
-
updateCompany,
|
|
13
|
-
waitForNotification
|
|
14
|
-
} from "./helpers/recordLocks.js";
|
|
15
|
-
test.describe("TC-LOCK-003: Accept mine conflict resolution and notification", () => {
|
|
16
|
-
test.describe.configure({ timeout: 9e4 });
|
|
17
|
-
test("should resolve conflict with accept_mine and notify incoming actor", async ({ request }) => {
|
|
18
|
-
const superadminToken = await getAuthToken(request, "superadmin");
|
|
19
|
-
const adminToken = await getAuthToken(request, "admin");
|
|
20
|
-
const superadminScopeCookie = buildScopeCookieFromToken(superadminToken);
|
|
21
|
-
const superadminScopeHeaders = superadminScopeCookie ? { cookie: superadminScopeCookie } : void 0;
|
|
22
|
-
let previousSettings = null;
|
|
23
|
-
let companyId = null;
|
|
24
|
-
let ownerLockToken = null;
|
|
25
|
-
try {
|
|
26
|
-
previousSettings = await getRecordLockSettings(request, superadminToken);
|
|
27
|
-
await saveRecordLockSettings(request, superadminToken, {
|
|
28
|
-
...previousSettings,
|
|
29
|
-
enabled: true,
|
|
30
|
-
strategy: "optimistic",
|
|
31
|
-
enabledResources: ["customers.company"],
|
|
32
|
-
notifyOnConflict: true
|
|
33
|
-
});
|
|
34
|
-
companyId = await createCompanyFixture(request, adminToken, `QA TC-LOCK-003 Company ${Date.now()}`);
|
|
35
|
-
const acquire = await acquireRecordLock(
|
|
36
|
-
request,
|
|
37
|
-
superadminToken,
|
|
38
|
-
"customers.company",
|
|
39
|
-
companyId,
|
|
40
|
-
superadminScopeHeaders
|
|
41
|
-
);
|
|
42
|
-
expect(acquire.status).toBe(200);
|
|
43
|
-
ownerLockToken = acquire.body?.lock?.token ?? null;
|
|
44
|
-
const baseLogId = acquire.body?.latestActionLogId ?? null;
|
|
45
|
-
expect(ownerLockToken).toBeTruthy();
|
|
46
|
-
expect(baseLogId).toBeTruthy();
|
|
47
|
-
const incomingName = `QA TC-LOCK-003 Incoming ${Date.now()}`;
|
|
48
|
-
const incomingUpdate = await updateCompany(request, adminToken, companyId, incomingName);
|
|
49
|
-
expect(incomingUpdate.status).toBe(200);
|
|
50
|
-
const conflictAttempt = await updateCompany(
|
|
51
|
-
request,
|
|
52
|
-
superadminToken,
|
|
53
|
-
companyId,
|
|
54
|
-
`QA TC-LOCK-003 Mine ${Date.now()}`,
|
|
55
|
-
{
|
|
56
|
-
token: ownerLockToken,
|
|
57
|
-
baseLogId,
|
|
58
|
-
resolution: "normal"
|
|
59
|
-
},
|
|
60
|
-
superadminScopeHeaders
|
|
61
|
-
);
|
|
62
|
-
expect(conflictAttempt.status).toBe(409);
|
|
63
|
-
expect(conflictAttempt.body?.code).toBe("record_lock_conflict");
|
|
64
|
-
const conflictId = conflictAttempt.body?.conflict?.id ?? null;
|
|
65
|
-
expect(conflictId).toBeTruthy();
|
|
66
|
-
await waitForNotification(
|
|
67
|
-
request,
|
|
68
|
-
superadminToken,
|
|
69
|
-
"record_locks.conflict.detected",
|
|
70
|
-
(item) => item.sourceEntityId === conflictId
|
|
71
|
-
);
|
|
72
|
-
const mineName = `QA TC-LOCK-003 Keep Mine ${Date.now()}`;
|
|
73
|
-
const resolveAttempt = await updateCompany(
|
|
74
|
-
request,
|
|
75
|
-
superadminToken,
|
|
76
|
-
companyId,
|
|
77
|
-
mineName,
|
|
78
|
-
{
|
|
79
|
-
token: ownerLockToken,
|
|
80
|
-
baseLogId,
|
|
81
|
-
resolution: "accept_mine",
|
|
82
|
-
conflictId
|
|
83
|
-
},
|
|
84
|
-
superadminScopeHeaders
|
|
85
|
-
);
|
|
86
|
-
expect(resolveAttempt.status).toBe(200);
|
|
87
|
-
ownerLockToken = null;
|
|
88
|
-
const finalName = await getCompanyDisplayName(request, adminToken, companyId);
|
|
89
|
-
expect(finalName).toBe(mineName);
|
|
90
|
-
const resolvedNotification = await waitForNotification(
|
|
91
|
-
request,
|
|
92
|
-
adminToken,
|
|
93
|
-
"record_locks.conflict.resolved",
|
|
94
|
-
(item) => item.sourceEntityId === conflictId
|
|
95
|
-
);
|
|
96
|
-
expect(resolvedNotification.bodyVariables?.resolution ?? "accept_mine").toBe("accept_mine");
|
|
97
|
-
} finally {
|
|
98
|
-
if (ownerLockToken && companyId) {
|
|
99
|
-
await releaseRecordLock(
|
|
100
|
-
request,
|
|
101
|
-
superadminToken,
|
|
102
|
-
"customers.company",
|
|
103
|
-
companyId,
|
|
104
|
-
ownerLockToken,
|
|
105
|
-
"cancelled",
|
|
106
|
-
void 0,
|
|
107
|
-
superadminScopeHeaders
|
|
108
|
-
).catch(() => {
|
|
109
|
-
});
|
|
110
|
-
}
|
|
111
|
-
await cleanupCompany(request, adminToken, companyId);
|
|
112
|
-
if (previousSettings) {
|
|
113
|
-
await saveRecordLockSettings(request, superadminToken, previousSettings).catch(() => {
|
|
114
|
-
});
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
});
|
|
118
|
-
});
|
|
119
|
-
//# sourceMappingURL=TC-LOCK-003.spec.js.map
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../../../../src/modules/record_locks/__integration__/TC-LOCK-003.spec.ts"],
|
|
4
|
-
"sourcesContent": ["import { expect, test } from '@playwright/test';\nimport { getAuthToken } from '@open-mercato/core/modules/core/__integration__/helpers/api';\nimport { createCompanyFixture } from '@open-mercato/core/modules/core/__integration__/helpers/crmFixtures';\nimport {\n acquireRecordLock,\n cleanupCompany,\n buildScopeCookieFromToken,\n getCompanyDisplayName,\n getRecordLockSettings,\n releaseRecordLock,\n saveRecordLockSettings,\n updateCompany,\n waitForNotification,\n type RecordLockSettings,\n} from './helpers/recordLocks';\n\n/**\n * TC-LOCK-003: Accept mine conflict resolution and notification\n */\ntest.describe('TC-LOCK-003: Accept mine conflict resolution and notification', () => {\n test.describe.configure({ timeout: 90_000 });\n\n test('should resolve conflict with accept_mine and notify incoming actor', async ({ request }) => {\n const superadminToken = await getAuthToken(request, 'superadmin');\n const adminToken = await getAuthToken(request, 'admin');\n const superadminScopeCookie = buildScopeCookieFromToken(superadminToken);\n const superadminScopeHeaders = superadminScopeCookie ? { cookie: superadminScopeCookie } : undefined;\n\n let previousSettings: RecordLockSettings | null = null;\n let companyId: string | null = null;\n let ownerLockToken: string | null = null;\n\n try {\n previousSettings = await getRecordLockSettings(request, superadminToken);\n await saveRecordLockSettings(request, superadminToken, {\n ...previousSettings,\n enabled: true,\n strategy: 'optimistic',\n enabledResources: ['customers.company'],\n notifyOnConflict: true,\n });\n\n companyId = await createCompanyFixture(request, adminToken, `QA TC-LOCK-003 Company ${Date.now()}`);\n\n const acquire = await acquireRecordLock(\n request,\n superadminToken,\n 'customers.company',\n companyId,\n superadminScopeHeaders,\n );\n expect(acquire.status).toBe(200);\n ownerLockToken = (acquire.body?.lock as { token?: string | null } | undefined)?.token ?? null;\n const baseLogId =\n (acquire.body as { latestActionLogId?: string | null } | null)?.latestActionLogId ?? null;\n expect(ownerLockToken).toBeTruthy();\n expect(baseLogId).toBeTruthy();\n\n const incomingName = `QA TC-LOCK-003 Incoming ${Date.now()}`;\n const incomingUpdate = await updateCompany(request, adminToken, companyId, incomingName);\n expect(incomingUpdate.status).toBe(200);\n\n const conflictAttempt = await updateCompany(\n request,\n superadminToken,\n companyId,\n `QA TC-LOCK-003 Mine ${Date.now()}`,\n {\n token: ownerLockToken,\n baseLogId,\n resolution: 'normal',\n },\n superadminScopeHeaders,\n );\n expect(conflictAttempt.status).toBe(409);\n expect(conflictAttempt.body?.code).toBe('record_lock_conflict');\n\n const conflictId =\n (conflictAttempt.body?.conflict as { id?: string } | undefined)?.id ?? null;\n expect(conflictId).toBeTruthy();\n\n await waitForNotification(\n request,\n superadminToken,\n 'record_locks.conflict.detected',\n (item) => item.sourceEntityId === conflictId,\n );\n\n const mineName = `QA TC-LOCK-003 Keep Mine ${Date.now()}`;\n const resolveAttempt = await updateCompany(\n request,\n superadminToken,\n companyId,\n mineName,\n {\n token: ownerLockToken,\n baseLogId,\n resolution: 'accept_mine',\n conflictId,\n },\n superadminScopeHeaders,\n );\n expect(resolveAttempt.status).toBe(200);\n\n ownerLockToken = null;\n\n const finalName = await getCompanyDisplayName(request, adminToken, companyId);\n expect(finalName).toBe(mineName);\n\n const resolvedNotification = await waitForNotification(\n request,\n adminToken,\n 'record_locks.conflict.resolved',\n (item) => item.sourceEntityId === conflictId,\n );\n expect(resolvedNotification.bodyVariables?.resolution ?? 'accept_mine').toBe('accept_mine');\n } finally {\n if (ownerLockToken && companyId) {\n await releaseRecordLock(\n request,\n superadminToken,\n 'customers.company',\n companyId,\n ownerLockToken,\n 'cancelled',\n undefined,\n superadminScopeHeaders,\n ).catch(() => {});\n }\n await cleanupCompany(request, adminToken, companyId);\n if (previousSettings) {\n await saveRecordLockSettings(request, superadminToken, previousSettings).catch(() => {});\n }\n }\n });\n});\n"],
|
|
5
|
-
"mappings": "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",
|
|
6
|
-
"names": []
|
|
7
|
-
}
|
|
@@ -1,119 +0,0 @@
|
|
|
1
|
-
import { expect, test } from "@playwright/test";
|
|
2
|
-
import { getAuthToken } from "@open-mercato/core/modules/core/__integration__/helpers/api";
|
|
3
|
-
import { createCompanyFixture } from "@open-mercato/core/modules/core/__integration__/helpers/crmFixtures";
|
|
4
|
-
import {
|
|
5
|
-
acquireRecordLock,
|
|
6
|
-
cleanupCompany,
|
|
7
|
-
buildScopeCookieFromToken,
|
|
8
|
-
getCompanyDisplayName,
|
|
9
|
-
getRecordLockSettings,
|
|
10
|
-
releaseRecordLock,
|
|
11
|
-
saveRecordLockSettings,
|
|
12
|
-
updateCompany,
|
|
13
|
-
waitForNotification
|
|
14
|
-
} from "./helpers/recordLocks.js";
|
|
15
|
-
test.describe("TC-LOCK-004: Merged conflict resolution and notification", () => {
|
|
16
|
-
test.describe.configure({ timeout: 9e4 });
|
|
17
|
-
test("should resolve conflict with merged resolution and notify incoming actor", async ({ request }) => {
|
|
18
|
-
const superadminToken = await getAuthToken(request, "superadmin");
|
|
19
|
-
const adminToken = await getAuthToken(request, "admin");
|
|
20
|
-
const superadminScopeCookie = buildScopeCookieFromToken(superadminToken);
|
|
21
|
-
const superadminScopeHeaders = superadminScopeCookie ? { cookie: superadminScopeCookie } : void 0;
|
|
22
|
-
let previousSettings = null;
|
|
23
|
-
let companyId = null;
|
|
24
|
-
let ownerLockToken = null;
|
|
25
|
-
try {
|
|
26
|
-
previousSettings = await getRecordLockSettings(request, superadminToken);
|
|
27
|
-
await saveRecordLockSettings(request, superadminToken, {
|
|
28
|
-
...previousSettings,
|
|
29
|
-
enabled: true,
|
|
30
|
-
strategy: "optimistic",
|
|
31
|
-
enabledResources: ["customers.company"],
|
|
32
|
-
notifyOnConflict: true
|
|
33
|
-
});
|
|
34
|
-
companyId = await createCompanyFixture(request, adminToken, `QA TC-LOCK-004 Company ${Date.now()}`);
|
|
35
|
-
const acquire = await acquireRecordLock(
|
|
36
|
-
request,
|
|
37
|
-
superadminToken,
|
|
38
|
-
"customers.company",
|
|
39
|
-
companyId,
|
|
40
|
-
superadminScopeHeaders
|
|
41
|
-
);
|
|
42
|
-
expect(acquire.status).toBe(200);
|
|
43
|
-
ownerLockToken = acquire.body?.lock?.token ?? null;
|
|
44
|
-
const baseLogId = acquire.body?.latestActionLogId ?? null;
|
|
45
|
-
expect(ownerLockToken).toBeTruthy();
|
|
46
|
-
expect(baseLogId).toBeTruthy();
|
|
47
|
-
const incomingName = `QA TC-LOCK-004 Incoming ${Date.now()}`;
|
|
48
|
-
const incomingUpdate = await updateCompany(request, adminToken, companyId, incomingName);
|
|
49
|
-
expect(incomingUpdate.status).toBe(200);
|
|
50
|
-
const conflictAttempt = await updateCompany(
|
|
51
|
-
request,
|
|
52
|
-
superadminToken,
|
|
53
|
-
companyId,
|
|
54
|
-
`QA TC-LOCK-004 Mine ${Date.now()}`,
|
|
55
|
-
{
|
|
56
|
-
token: ownerLockToken,
|
|
57
|
-
baseLogId,
|
|
58
|
-
resolution: "normal"
|
|
59
|
-
},
|
|
60
|
-
superadminScopeHeaders
|
|
61
|
-
);
|
|
62
|
-
expect(conflictAttempt.status).toBe(409);
|
|
63
|
-
expect(conflictAttempt.body?.code).toBe("record_lock_conflict");
|
|
64
|
-
const conflictId = conflictAttempt.body?.conflict?.id ?? null;
|
|
65
|
-
expect(conflictId).toBeTruthy();
|
|
66
|
-
await waitForNotification(
|
|
67
|
-
request,
|
|
68
|
-
superadminToken,
|
|
69
|
-
"record_locks.conflict.detected",
|
|
70
|
-
(item) => item.sourceEntityId === conflictId
|
|
71
|
-
);
|
|
72
|
-
const mergedName = `QA TC-LOCK-004 Merged ${Date.now()}`;
|
|
73
|
-
const mergedAttempt = await updateCompany(
|
|
74
|
-
request,
|
|
75
|
-
superadminToken,
|
|
76
|
-
companyId,
|
|
77
|
-
mergedName,
|
|
78
|
-
{
|
|
79
|
-
token: ownerLockToken,
|
|
80
|
-
baseLogId,
|
|
81
|
-
resolution: "merged",
|
|
82
|
-
conflictId
|
|
83
|
-
},
|
|
84
|
-
superadminScopeHeaders
|
|
85
|
-
);
|
|
86
|
-
expect(mergedAttempt.status).toBe(200);
|
|
87
|
-
ownerLockToken = null;
|
|
88
|
-
const finalName = await getCompanyDisplayName(request, adminToken, companyId);
|
|
89
|
-
expect(finalName).toBe(mergedName);
|
|
90
|
-
const resolvedNotification = await waitForNotification(
|
|
91
|
-
request,
|
|
92
|
-
adminToken,
|
|
93
|
-
"record_locks.conflict.resolved",
|
|
94
|
-
(item) => item.sourceEntityId === conflictId
|
|
95
|
-
);
|
|
96
|
-
expect(resolvedNotification.bodyVariables?.resolution).toBe("merged");
|
|
97
|
-
} finally {
|
|
98
|
-
if (ownerLockToken && companyId) {
|
|
99
|
-
await releaseRecordLock(
|
|
100
|
-
request,
|
|
101
|
-
superadminToken,
|
|
102
|
-
"customers.company",
|
|
103
|
-
companyId,
|
|
104
|
-
ownerLockToken,
|
|
105
|
-
"cancelled",
|
|
106
|
-
void 0,
|
|
107
|
-
superadminScopeHeaders
|
|
108
|
-
).catch(() => {
|
|
109
|
-
});
|
|
110
|
-
}
|
|
111
|
-
await cleanupCompany(request, adminToken, companyId);
|
|
112
|
-
if (previousSettings) {
|
|
113
|
-
await saveRecordLockSettings(request, superadminToken, previousSettings).catch(() => {
|
|
114
|
-
});
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
});
|
|
118
|
-
});
|
|
119
|
-
//# sourceMappingURL=TC-LOCK-004.spec.js.map
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../../../../src/modules/record_locks/__integration__/TC-LOCK-004.spec.ts"],
|
|
4
|
-
"sourcesContent": ["import { expect, test } from '@playwright/test';\nimport { getAuthToken } from '@open-mercato/core/modules/core/__integration__/helpers/api';\nimport { createCompanyFixture } from '@open-mercato/core/modules/core/__integration__/helpers/crmFixtures';\nimport {\n acquireRecordLock,\n cleanupCompany,\n buildScopeCookieFromToken,\n getCompanyDisplayName,\n getRecordLockSettings,\n releaseRecordLock,\n saveRecordLockSettings,\n updateCompany,\n waitForNotification,\n type RecordLockSettings,\n} from './helpers/recordLocks';\n\n/**\n * TC-LOCK-004: Merged conflict resolution and notification\n */\ntest.describe('TC-LOCK-004: Merged conflict resolution and notification', () => {\n test.describe.configure({ timeout: 90_000 });\n\n test('should resolve conflict with merged resolution and notify incoming actor', async ({ request }) => {\n const superadminToken = await getAuthToken(request, 'superadmin');\n const adminToken = await getAuthToken(request, 'admin');\n const superadminScopeCookie = buildScopeCookieFromToken(superadminToken);\n const superadminScopeHeaders = superadminScopeCookie ? { cookie: superadminScopeCookie } : undefined;\n\n let previousSettings: RecordLockSettings | null = null;\n let companyId: string | null = null;\n let ownerLockToken: string | null = null;\n\n try {\n previousSettings = await getRecordLockSettings(request, superadminToken);\n await saveRecordLockSettings(request, superadminToken, {\n ...previousSettings,\n enabled: true,\n strategy: 'optimistic',\n enabledResources: ['customers.company'],\n notifyOnConflict: true,\n });\n\n companyId = await createCompanyFixture(request, adminToken, `QA TC-LOCK-004 Company ${Date.now()}`);\n\n const acquire = await acquireRecordLock(\n request,\n superadminToken,\n 'customers.company',\n companyId,\n superadminScopeHeaders,\n );\n expect(acquire.status).toBe(200);\n ownerLockToken = (acquire.body?.lock as { token?: string | null } | undefined)?.token ?? null;\n const baseLogId =\n (acquire.body as { latestActionLogId?: string | null } | null)?.latestActionLogId ?? null;\n expect(ownerLockToken).toBeTruthy();\n expect(baseLogId).toBeTruthy();\n\n const incomingName = `QA TC-LOCK-004 Incoming ${Date.now()}`;\n const incomingUpdate = await updateCompany(request, adminToken, companyId, incomingName);\n expect(incomingUpdate.status).toBe(200);\n\n const conflictAttempt = await updateCompany(\n request,\n superadminToken,\n companyId,\n `QA TC-LOCK-004 Mine ${Date.now()}`,\n {\n token: ownerLockToken,\n baseLogId,\n resolution: 'normal',\n },\n superadminScopeHeaders,\n );\n expect(conflictAttempt.status).toBe(409);\n expect(conflictAttempt.body?.code).toBe('record_lock_conflict');\n\n const conflictId =\n (conflictAttempt.body?.conflict as { id?: string } | undefined)?.id ?? null;\n expect(conflictId).toBeTruthy();\n\n await waitForNotification(\n request,\n superadminToken,\n 'record_locks.conflict.detected',\n (item) => item.sourceEntityId === conflictId,\n );\n\n const mergedName = `QA TC-LOCK-004 Merged ${Date.now()}`;\n const mergedAttempt = await updateCompany(\n request,\n superadminToken,\n companyId,\n mergedName,\n {\n token: ownerLockToken,\n baseLogId,\n resolution: 'merged',\n conflictId,\n },\n superadminScopeHeaders,\n );\n expect(mergedAttempt.status).toBe(200);\n\n ownerLockToken = null;\n\n const finalName = await getCompanyDisplayName(request, adminToken, companyId);\n expect(finalName).toBe(mergedName);\n\n const resolvedNotification = await waitForNotification(\n request,\n adminToken,\n 'record_locks.conflict.resolved',\n (item) => item.sourceEntityId === conflictId,\n );\n expect(resolvedNotification.bodyVariables?.resolution).toBe('merged');\n } finally {\n if (ownerLockToken && companyId) {\n await releaseRecordLock(\n request,\n superadminToken,\n 'customers.company',\n companyId,\n ownerLockToken,\n 'cancelled',\n undefined,\n superadminScopeHeaders,\n ).catch(() => {});\n }\n await cleanupCompany(request, adminToken, companyId);\n if (previousSettings) {\n await saveRecordLockSettings(request, superadminToken, previousSettings).catch(() => {});\n }\n }\n });\n});\n"],
|
|
5
|
-
"mappings": "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",
|
|
6
|
-
"names": []
|
|
7
|
-
}
|
|
@@ -1,90 +0,0 @@
|
|
|
1
|
-
import { expect, test } from "@playwright/test";
|
|
2
|
-
import { getAuthToken } from "@open-mercato/core/modules/core/__integration__/helpers/api";
|
|
3
|
-
import { createCompanyFixture } from "@open-mercato/core/modules/core/__integration__/helpers/crmFixtures";
|
|
4
|
-
import {
|
|
5
|
-
acquireRecordLock,
|
|
6
|
-
cleanupCompany,
|
|
7
|
-
forceReleaseRecordLock,
|
|
8
|
-
getRecordLockSettings,
|
|
9
|
-
listNotificationsByType,
|
|
10
|
-
saveRecordLockSettings,
|
|
11
|
-
updateCompany,
|
|
12
|
-
waitForNotification
|
|
13
|
-
} from "./helpers/recordLocks.js";
|
|
14
|
-
test.describe("TC-LOCK-005: Pessimistic force release and takeover", () => {
|
|
15
|
-
test.describe.configure({ timeout: 9e4 });
|
|
16
|
-
test("admin can force release lock and continue mutation flow", async ({ request }) => {
|
|
17
|
-
const superadminToken = await getAuthToken(request, "superadmin");
|
|
18
|
-
const adminToken = await getAuthToken(request, "admin");
|
|
19
|
-
let previousSettings = null;
|
|
20
|
-
let companyId = null;
|
|
21
|
-
try {
|
|
22
|
-
previousSettings = await getRecordLockSettings(request, superadminToken);
|
|
23
|
-
await saveRecordLockSettings(request, superadminToken, {
|
|
24
|
-
...previousSettings,
|
|
25
|
-
enabled: true,
|
|
26
|
-
strategy: "pessimistic",
|
|
27
|
-
enabledResources: ["customers.company"],
|
|
28
|
-
allowForceUnlock: true
|
|
29
|
-
});
|
|
30
|
-
companyId = await createCompanyFixture(request, adminToken, `QA TC-LOCK-005 Company ${Date.now()}`);
|
|
31
|
-
const ownerAcquire = await acquireRecordLock(request, superadminToken, "customers.company", companyId);
|
|
32
|
-
expect(ownerAcquire.status).toBe(200);
|
|
33
|
-
expect(ownerAcquire.body?.ok).toBe(true);
|
|
34
|
-
const ownerLockToken = ownerAcquire.body?.lock?.token ?? null;
|
|
35
|
-
expect(ownerLockToken).toBeTruthy();
|
|
36
|
-
const blockedUpdate = await updateCompany(
|
|
37
|
-
request,
|
|
38
|
-
adminToken,
|
|
39
|
-
companyId,
|
|
40
|
-
`QA TC-LOCK-005 Blocked ${Date.now()}`
|
|
41
|
-
);
|
|
42
|
-
expect(blockedUpdate.status).toBe(423);
|
|
43
|
-
expect(blockedUpdate.body?.code).toBe("record_locked");
|
|
44
|
-
const existingForceReleaseNotifications = await listNotificationsByType(
|
|
45
|
-
request,
|
|
46
|
-
superadminToken,
|
|
47
|
-
"record_locks.lock.force_released"
|
|
48
|
-
);
|
|
49
|
-
const knownNotificationIds = new Set(existingForceReleaseNotifications.map((entry) => entry.id));
|
|
50
|
-
const forceRelease = await forceReleaseRecordLock(
|
|
51
|
-
request,
|
|
52
|
-
adminToken,
|
|
53
|
-
"customers.company",
|
|
54
|
-
companyId,
|
|
55
|
-
"qa_tc_lock_005_takeover"
|
|
56
|
-
);
|
|
57
|
-
expect(forceRelease.status).toBe(200);
|
|
58
|
-
expect(forceRelease.body?.released).toBe(true);
|
|
59
|
-
const nextLock = forceRelease.body?.lock ?? null;
|
|
60
|
-
if (nextLock) {
|
|
61
|
-
expect(nextLock.status).toBe("active");
|
|
62
|
-
expect(nextLock.lockedByUserId).toBeTruthy();
|
|
63
|
-
}
|
|
64
|
-
const forceReleaseNotification = await waitForNotification(
|
|
65
|
-
request,
|
|
66
|
-
superadminToken,
|
|
67
|
-
"record_locks.lock.force_released",
|
|
68
|
-
(item) => !knownNotificationIds.has(item.id),
|
|
69
|
-
3e4,
|
|
70
|
-
500
|
|
71
|
-
);
|
|
72
|
-
expect(forceReleaseNotification.type).toBe("record_locks.lock.force_released");
|
|
73
|
-
const updateAfterForceRelease = await updateCompany(
|
|
74
|
-
request,
|
|
75
|
-
adminToken,
|
|
76
|
-
companyId,
|
|
77
|
-
`QA TC-LOCK-005 Updated ${Date.now()}`
|
|
78
|
-
);
|
|
79
|
-
expect(updateAfterForceRelease.status).toBe(200);
|
|
80
|
-
expect(updateAfterForceRelease.body?.ok).toBe(true);
|
|
81
|
-
} finally {
|
|
82
|
-
await cleanupCompany(request, adminToken, companyId);
|
|
83
|
-
if (previousSettings) {
|
|
84
|
-
await saveRecordLockSettings(request, superadminToken, previousSettings).catch(() => {
|
|
85
|
-
});
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
});
|
|
89
|
-
});
|
|
90
|
-
//# sourceMappingURL=TC-LOCK-005.spec.js.map
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../../../../src/modules/record_locks/__integration__/TC-LOCK-005.spec.ts"],
|
|
4
|
-
"sourcesContent": ["import { expect, test } from '@playwright/test';\nimport { getAuthToken } from '@open-mercato/core/modules/core/__integration__/helpers/api';\nimport { createCompanyFixture } from '@open-mercato/core/modules/core/__integration__/helpers/crmFixtures';\nimport {\n acquireRecordLock,\n cleanupCompany,\n forceReleaseRecordLock,\n getRecordLockSettings,\n listNotificationsByType,\n saveRecordLockSettings,\n updateCompany,\n waitForNotification,\n type RecordLockSettings,\n} from './helpers/recordLocks';\n\n/**\n * TC-LOCK-005: Pessimistic force release and takeover\n */\ntest.describe('TC-LOCK-005: Pessimistic force release and takeover', () => {\n test.describe.configure({ timeout: 90_000 });\n\n test('admin can force release lock and continue mutation flow', async ({ request }) => {\n const superadminToken = await getAuthToken(request, 'superadmin');\n const adminToken = await getAuthToken(request, 'admin');\n\n let previousSettings: RecordLockSettings | null = null;\n let companyId: string | null = null;\n\n try {\n previousSettings = await getRecordLockSettings(request, superadminToken);\n await saveRecordLockSettings(request, superadminToken, {\n ...previousSettings,\n enabled: true,\n strategy: 'pessimistic',\n enabledResources: ['customers.company'],\n allowForceUnlock: true,\n });\n\n companyId = await createCompanyFixture(request, adminToken, `QA TC-LOCK-005 Company ${Date.now()}`);\n\n const ownerAcquire = await acquireRecordLock(request, superadminToken, 'customers.company', companyId);\n expect(ownerAcquire.status).toBe(200);\n expect(ownerAcquire.body?.ok).toBe(true);\n const ownerLockToken =\n (ownerAcquire.body?.lock as { token?: string | null } | undefined)?.token ?? null;\n expect(ownerLockToken).toBeTruthy();\n\n const blockedUpdate = await updateCompany(\n request,\n adminToken,\n companyId,\n `QA TC-LOCK-005 Blocked ${Date.now()}`,\n );\n expect(blockedUpdate.status).toBe(423);\n expect(blockedUpdate.body?.code).toBe('record_locked');\n\n const existingForceReleaseNotifications = await listNotificationsByType(\n request,\n superadminToken,\n 'record_locks.lock.force_released',\n );\n const knownNotificationIds = new Set(existingForceReleaseNotifications.map((entry) => entry.id));\n\n const forceRelease = await forceReleaseRecordLock(\n request,\n adminToken,\n 'customers.company',\n companyId,\n 'qa_tc_lock_005_takeover',\n );\n expect(forceRelease.status).toBe(200);\n expect(forceRelease.body?.released).toBe(true);\n\n const nextLock = (forceRelease.body?.lock as { id?: string; status?: string; lockedByUserId?: string } | undefined) ?? null;\n if (nextLock) {\n expect(nextLock.status).toBe('active');\n expect(nextLock.lockedByUserId).toBeTruthy();\n }\n\n const forceReleaseNotification = await waitForNotification(\n request,\n superadminToken,\n 'record_locks.lock.force_released',\n (item) =>\n !knownNotificationIds.has(item.id),\n 30_000,\n 500,\n );\n expect(forceReleaseNotification.type).toBe('record_locks.lock.force_released');\n\n const updateAfterForceRelease = await updateCompany(\n request,\n adminToken,\n companyId,\n `QA TC-LOCK-005 Updated ${Date.now()}`,\n );\n expect(updateAfterForceRelease.status).toBe(200);\n expect(updateAfterForceRelease.body?.ok).toBe(true);\n } finally {\n await cleanupCompany(request, adminToken, companyId);\n if (previousSettings) {\n await saveRecordLockSettings(request, superadminToken, previousSettings).catch(() => {});\n }\n }\n });\n});\n"],
|
|
5
|
-
"mappings": "AAAA,SAAS,QAAQ,YAAY;AAC7B,SAAS,oBAAoB;AAC7B,SAAS,4BAA4B;AACrC;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OAEK;AAKP,KAAK,SAAS,uDAAuD,MAAM;AACzE,OAAK,SAAS,UAAU,EAAE,SAAS,IAAO,CAAC;AAE3C,OAAK,2DAA2D,OAAO,EAAE,QAAQ,MAAM;AACrF,UAAM,kBAAkB,MAAM,aAAa,SAAS,YAAY;AAChE,UAAM,aAAa,MAAM,aAAa,SAAS,OAAO;AAEtD,QAAI,mBAA8C;AAClD,QAAI,YAA2B;AAE/B,QAAI;AACF,yBAAmB,MAAM,sBAAsB,SAAS,eAAe;AACvE,YAAM,uBAAuB,SAAS,iBAAiB;AAAA,QACrD,GAAG;AAAA,QACH,SAAS;AAAA,QACT,UAAU;AAAA,QACV,kBAAkB,CAAC,mBAAmB;AAAA,QACtC,kBAAkB;AAAA,MACpB,CAAC;AAED,kBAAY,MAAM,qBAAqB,SAAS,YAAY,0BAA0B,KAAK,IAAI,CAAC,EAAE;AAElG,YAAM,eAAe,MAAM,kBAAkB,SAAS,iBAAiB,qBAAqB,SAAS;AACrG,aAAO,aAAa,MAAM,EAAE,KAAK,GAAG;AACpC,aAAO,aAAa,MAAM,EAAE,EAAE,KAAK,IAAI;AACvC,YAAM,iBACH,aAAa,MAAM,MAAgD,SAAS;AAC/E,aAAO,cAAc,EAAE,WAAW;AAElC,YAAM,gBAAgB,MAAM;AAAA,QAC1B;AAAA,QACA;AAAA,QACA;AAAA,QACA,0BAA0B,KAAK,IAAI,CAAC;AAAA,MACtC;AACA,aAAO,cAAc,MAAM,EAAE,KAAK,GAAG;AACrC,aAAO,cAAc,MAAM,IAAI,EAAE,KAAK,eAAe;AAErD,YAAM,oCAAoC,MAAM;AAAA,QAC9C;AAAA,QACA;AAAA,QACA;AAAA,MACF;AACA,YAAM,uBAAuB,IAAI,IAAI,kCAAkC,IAAI,CAAC,UAAU,MAAM,EAAE,CAAC;AAE/F,YAAM,eAAe,MAAM;AAAA,QACzB;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF;AACA,aAAO,aAAa,MAAM,EAAE,KAAK,GAAG;AACpC,aAAO,aAAa,MAAM,QAAQ,EAAE,KAAK,IAAI;AAE7C,YAAM,WAAY,aAAa,MAAM,QAAkF;AACvH,UAAI,UAAU;AACZ,eAAO,SAAS,MAAM,EAAE,KAAK,QAAQ;AACrC,eAAO,SAAS,cAAc,EAAE,WAAW;AAAA,MAC7C;AAEA,YAAM,2BAA2B,MAAM;AAAA,QACrC;AAAA,QACA;AAAA,QACA;AAAA,QACA,CAAC,SACC,CAAC,qBAAqB,IAAI,KAAK,EAAE;AAAA,QACnC;AAAA,QACA;AAAA,MACF;AACA,aAAO,yBAAyB,IAAI,EAAE,KAAK,kCAAkC;AAE7E,YAAM,0BAA0B,MAAM;AAAA,QACpC;AAAA,QACA;AAAA,QACA;AAAA,QACA,0BAA0B,KAAK,IAAI,CAAC;AAAA,MACtC;AACA,aAAO,wBAAwB,MAAM,EAAE,KAAK,GAAG;AAC/C,aAAO,wBAAwB,MAAM,EAAE,EAAE,KAAK,IAAI;AAAA,IACpD,UAAE;AACA,YAAM,eAAe,SAAS,YAAY,SAAS;AACnD,UAAI,kBAAkB;AACpB,cAAM,uBAAuB,SAAS,iBAAiB,gBAAgB,EAAE,MAAM,MAAM;AAAA,QAAC,CAAC;AAAA,MACzF;AAAA,IACF;AAAA,EACF,CAAC;AACH,CAAC;",
|
|
6
|
-
"names": []
|
|
7
|
-
}
|