@lodashventure/medusa-login-provider 4.1.0 → 4.1.2
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/.medusa/server/src/providers/line/__tests__/line-api.mock.test.js +472 -0
- package/.medusa/server/src/providers/line/__tests__/service.test.js +438 -0
- package/.medusa/server/src/providers/line/__tests__/utils.test.js +351 -0
- package/.medusa/server/src/providers/line/service.js +201 -51
- package/.medusa/server/src/providers/line/types.js +3 -0
- package/.medusa/server/src/providers/line/utils.js +119 -0
- package/package.json +21 -2
|
@@ -0,0 +1,438 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const service_1 = __importDefault(require("../service"));
|
|
7
|
+
const utils_1 = require("@medusajs/framework/utils");
|
|
8
|
+
const jsonwebtoken_1 = __importDefault(require("jsonwebtoken"));
|
|
9
|
+
const crypto_1 = __importDefault(require("crypto"));
|
|
10
|
+
// Mock dependencies
|
|
11
|
+
jest.mock("jsonwebtoken");
|
|
12
|
+
jest.mock("crypto");
|
|
13
|
+
// Mock fetch globally
|
|
14
|
+
global.fetch = jest.fn();
|
|
15
|
+
describe("LineProviderService", () => {
|
|
16
|
+
let service;
|
|
17
|
+
let mockLogger;
|
|
18
|
+
let mockCustomerService;
|
|
19
|
+
let mockAuthIdentityService;
|
|
20
|
+
let mockFetch;
|
|
21
|
+
let mockCrypto;
|
|
22
|
+
let mockJwt;
|
|
23
|
+
const defaultOptions = {
|
|
24
|
+
lineChannelId: "1234567890",
|
|
25
|
+
lineChannelSecret: "test-secret",
|
|
26
|
+
lineRedirectUrl: "https://example.com/callback",
|
|
27
|
+
autoCreateCustomer: true,
|
|
28
|
+
syncProfileData: true,
|
|
29
|
+
};
|
|
30
|
+
beforeEach(() => {
|
|
31
|
+
jest.clearAllMocks();
|
|
32
|
+
mockFetch = global.fetch;
|
|
33
|
+
mockCrypto = crypto_1.default;
|
|
34
|
+
mockJwt = jsonwebtoken_1.default;
|
|
35
|
+
mockLogger = {
|
|
36
|
+
info: jest.fn(),
|
|
37
|
+
error: jest.fn(),
|
|
38
|
+
warn: jest.fn(),
|
|
39
|
+
debug: jest.fn(),
|
|
40
|
+
};
|
|
41
|
+
mockCustomerService = {
|
|
42
|
+
create: jest.fn(),
|
|
43
|
+
update: jest.fn(),
|
|
44
|
+
retrieve: jest.fn(),
|
|
45
|
+
listAndCount: jest.fn(),
|
|
46
|
+
};
|
|
47
|
+
mockAuthIdentityService = {
|
|
48
|
+
create: jest.fn(),
|
|
49
|
+
update: jest.fn(),
|
|
50
|
+
retrieve: jest.fn(),
|
|
51
|
+
setState: jest.fn(),
|
|
52
|
+
getState: jest.fn(),
|
|
53
|
+
};
|
|
54
|
+
service = new service_1.default({
|
|
55
|
+
logger: mockLogger,
|
|
56
|
+
customerService: mockCustomerService,
|
|
57
|
+
}, defaultOptions);
|
|
58
|
+
// Mock crypto.randomBytes
|
|
59
|
+
const mockBuffer = Buffer.from("a".repeat(32));
|
|
60
|
+
mockCrypto.randomBytes.mockReturnValue(mockBuffer);
|
|
61
|
+
});
|
|
62
|
+
describe("validateOptions", () => {
|
|
63
|
+
it("should validate required options", () => {
|
|
64
|
+
expect(() => {
|
|
65
|
+
service_1.default.validateOptions({});
|
|
66
|
+
}).toThrow("line channel id is required");
|
|
67
|
+
expect(() => {
|
|
68
|
+
service_1.default.validateOptions({
|
|
69
|
+
lineChannelId: "123",
|
|
70
|
+
});
|
|
71
|
+
}).toThrow("line channel secret is required");
|
|
72
|
+
expect(() => {
|
|
73
|
+
service_1.default.validateOptions({
|
|
74
|
+
lineChannelId: "123",
|
|
75
|
+
lineChannelSecret: "secret",
|
|
76
|
+
});
|
|
77
|
+
}).not.toThrow(); // Redirect URL is now optional
|
|
78
|
+
// Validation should pass with just channel ID and secret
|
|
79
|
+
});
|
|
80
|
+
});
|
|
81
|
+
describe("register", () => {
|
|
82
|
+
it("should throw NOT_ALLOWED error", async () => {
|
|
83
|
+
await expect(service.register({}, mockAuthIdentityService)).rejects.toThrow(utils_1.MedusaError);
|
|
84
|
+
});
|
|
85
|
+
});
|
|
86
|
+
describe("authenticate", () => {
|
|
87
|
+
it("should return redirect URL for LINE OAuth", async () => {
|
|
88
|
+
mockAuthIdentityService.setState.mockResolvedValue(undefined);
|
|
89
|
+
const result = await service.authenticate({ body: { callback_url: "https://example.com/callback" } }, mockAuthIdentityService);
|
|
90
|
+
expect(result.success).toBe(true);
|
|
91
|
+
expect(result.location).toContain("https://access.line.me/oauth2/v2.1/authorize");
|
|
92
|
+
expect(result.location).toContain("client_id=1234567890");
|
|
93
|
+
expect(result.location).toContain("scope=profile%20openid%20email");
|
|
94
|
+
expect(mockAuthIdentityService.setState).toHaveBeenCalled();
|
|
95
|
+
});
|
|
96
|
+
it("should handle authentication errors", async () => {
|
|
97
|
+
const result = await service.authenticate({
|
|
98
|
+
query: {
|
|
99
|
+
error: "access_denied",
|
|
100
|
+
error_description: "User denied access",
|
|
101
|
+
error_uri: "https://example.com/error",
|
|
102
|
+
},
|
|
103
|
+
}, mockAuthIdentityService);
|
|
104
|
+
expect(result.success).toBe(false);
|
|
105
|
+
expect(result.error).toContain("User denied access");
|
|
106
|
+
});
|
|
107
|
+
});
|
|
108
|
+
describe("validateCallback", () => {
|
|
109
|
+
const mockTokenResponse = {
|
|
110
|
+
access_token: "test-access-token",
|
|
111
|
+
id_token: "test-id-token",
|
|
112
|
+
refresh_token: "test-refresh-token",
|
|
113
|
+
expires_in: 2592000,
|
|
114
|
+
scope: "profile openid",
|
|
115
|
+
token_type: "Bearer",
|
|
116
|
+
};
|
|
117
|
+
const mockProfile = {
|
|
118
|
+
userId: "U1234567890",
|
|
119
|
+
displayName: "Test User",
|
|
120
|
+
pictureUrl: "https://example.com/picture.jpg",
|
|
121
|
+
};
|
|
122
|
+
const mockIdTokenPayload = {
|
|
123
|
+
iss: "https://access.line.me",
|
|
124
|
+
sub: "U1234567890",
|
|
125
|
+
aud: "1234567890",
|
|
126
|
+
exp: Math.floor(Date.now() / 1000) + 3600,
|
|
127
|
+
iat: Math.floor(Date.now() / 1000),
|
|
128
|
+
name: "Test User",
|
|
129
|
+
picture: "https://example.com/picture.jpg",
|
|
130
|
+
};
|
|
131
|
+
it("should handle missing authorization code", async () => {
|
|
132
|
+
const result = await service.validateCallback({ query: {}, body: {} }, mockAuthIdentityService);
|
|
133
|
+
expect(result.success).toBe(false);
|
|
134
|
+
expect(result.error).toBe("No authorization code provided");
|
|
135
|
+
});
|
|
136
|
+
it("should handle missing state", async () => {
|
|
137
|
+
const result = await service.validateCallback({ query: { code: "test-code" }, body: {} }, mockAuthIdentityService);
|
|
138
|
+
expect(result.success).toBe(false);
|
|
139
|
+
expect(result.error).toBe("No state parameter provided");
|
|
140
|
+
});
|
|
141
|
+
it("should handle invalid state", async () => {
|
|
142
|
+
mockAuthIdentityService.getState.mockResolvedValue(null);
|
|
143
|
+
const result = await service.validateCallback({ query: { code: "test-code", state: "invalid-state" }, body: {} }, mockAuthIdentityService);
|
|
144
|
+
expect(result.success).toBe(false);
|
|
145
|
+
expect(result.error).toBe("Invalid state or session expired");
|
|
146
|
+
});
|
|
147
|
+
it("should handle OAuth errors", async () => {
|
|
148
|
+
const result = await service.validateCallback({
|
|
149
|
+
query: {
|
|
150
|
+
error: "invalid_request",
|
|
151
|
+
error_description: "Invalid request",
|
|
152
|
+
},
|
|
153
|
+
body: {},
|
|
154
|
+
}, mockAuthIdentityService);
|
|
155
|
+
expect(result.success).toBe(false);
|
|
156
|
+
expect(result.error).toContain("Invalid request");
|
|
157
|
+
});
|
|
158
|
+
it("should successfully validate callback with complete flow", async () => {
|
|
159
|
+
// Setup mocks
|
|
160
|
+
mockAuthIdentityService.getState.mockResolvedValue({
|
|
161
|
+
callback_url: "https://example.com/callback",
|
|
162
|
+
});
|
|
163
|
+
// Mock token exchange
|
|
164
|
+
mockFetch.mockResolvedValueOnce({
|
|
165
|
+
ok: true,
|
|
166
|
+
json: () => Promise.resolve(mockTokenResponse),
|
|
167
|
+
});
|
|
168
|
+
// Mock ID token verification
|
|
169
|
+
mockJwt.decode.mockReturnValue({
|
|
170
|
+
payload: mockIdTokenPayload,
|
|
171
|
+
});
|
|
172
|
+
// Mock profile fetch
|
|
173
|
+
mockFetch.mockResolvedValueOnce({
|
|
174
|
+
ok: true,
|
|
175
|
+
json: () => Promise.resolve(mockProfile),
|
|
176
|
+
});
|
|
177
|
+
// Mock auth identity creation (new user)
|
|
178
|
+
mockAuthIdentityService.retrieve.mockRejectedValue(new utils_1.MedusaError(utils_1.MedusaError.Types.NOT_FOUND, "Not found"));
|
|
179
|
+
const mockAuthIdentity = {
|
|
180
|
+
entity_id: "U1234567890",
|
|
181
|
+
user_metadata: {
|
|
182
|
+
line_user_id: "U1234567890",
|
|
183
|
+
display_name: "Test User",
|
|
184
|
+
picture_url: "https://example.com/picture.jpg",
|
|
185
|
+
name: "Test User",
|
|
186
|
+
picture: "https://example.com/picture.jpg",
|
|
187
|
+
},
|
|
188
|
+
};
|
|
189
|
+
mockAuthIdentityService.create.mockResolvedValue(mockAuthIdentity);
|
|
190
|
+
// Mock customer creation
|
|
191
|
+
const mockCustomer = {
|
|
192
|
+
id: "cust_123",
|
|
193
|
+
email: "line-U1234567890@line.local",
|
|
194
|
+
first_name: "Test",
|
|
195
|
+
last_name: "User",
|
|
196
|
+
};
|
|
197
|
+
mockCustomerService.create.mockResolvedValue(mockCustomer);
|
|
198
|
+
const result = await service.validateCallback({ query: { code: "test-code", state: "valid-state" }, body: {} }, mockAuthIdentityService);
|
|
199
|
+
expect(result.success).toBe(true);
|
|
200
|
+
expect(result.authIdentity).toBe(mockAuthIdentity);
|
|
201
|
+
});
|
|
202
|
+
it("should handle existing user with profile sync", async () => {
|
|
203
|
+
mockAuthIdentityService.getState.mockResolvedValue({
|
|
204
|
+
callback_url: "https://example.com/callback",
|
|
205
|
+
});
|
|
206
|
+
mockFetch.mockResolvedValueOnce({
|
|
207
|
+
ok: true,
|
|
208
|
+
json: () => Promise.resolve(mockTokenResponse),
|
|
209
|
+
});
|
|
210
|
+
mockJwt.decode.mockReturnValue({
|
|
211
|
+
payload: mockIdTokenPayload,
|
|
212
|
+
});
|
|
213
|
+
mockFetch.mockResolvedValueOnce({
|
|
214
|
+
ok: true,
|
|
215
|
+
json: () => Promise.resolve(mockProfile),
|
|
216
|
+
});
|
|
217
|
+
// Mock existing auth identity
|
|
218
|
+
const existingAuthIdentity = {
|
|
219
|
+
entity_id: "U1234567890",
|
|
220
|
+
user_metadata: {
|
|
221
|
+
line_user_id: "U1234567890",
|
|
222
|
+
display_name: "Old Name",
|
|
223
|
+
},
|
|
224
|
+
};
|
|
225
|
+
mockAuthIdentityService.retrieve.mockResolvedValue(existingAuthIdentity);
|
|
226
|
+
const updatedAuthIdentity = {
|
|
227
|
+
...existingAuthIdentity,
|
|
228
|
+
user_metadata: {
|
|
229
|
+
line_user_id: "U1234567890",
|
|
230
|
+
display_name: "Test User",
|
|
231
|
+
picture_url: "https://example.com/picture.jpg",
|
|
232
|
+
},
|
|
233
|
+
};
|
|
234
|
+
mockAuthIdentityService.update.mockResolvedValue(updatedAuthIdentity);
|
|
235
|
+
// Mock existing customer
|
|
236
|
+
mockCustomerService.listAndCount.mockResolvedValue([
|
|
237
|
+
[{
|
|
238
|
+
id: "cust_existing",
|
|
239
|
+
metadata: { line_user_id: "U1234567890" }
|
|
240
|
+
}],
|
|
241
|
+
1
|
|
242
|
+
]);
|
|
243
|
+
const result = await service.validateCallback({ query: { code: "test-code", state: "valid-state" }, body: {} }, mockAuthIdentityService);
|
|
244
|
+
expect(result.success).toBe(true);
|
|
245
|
+
expect(mockAuthIdentityService.update).toHaveBeenCalled();
|
|
246
|
+
});
|
|
247
|
+
});
|
|
248
|
+
describe("verifyIdToken", () => {
|
|
249
|
+
beforeEach(() => {
|
|
250
|
+
jest.spyOn(Date, "now").mockReturnValue(1000000);
|
|
251
|
+
});
|
|
252
|
+
afterEach(() => {
|
|
253
|
+
Date.now.mockRestore();
|
|
254
|
+
});
|
|
255
|
+
it("should verify valid ID token", async () => {
|
|
256
|
+
const payload = {
|
|
257
|
+
iss: "https://access.line.me",
|
|
258
|
+
sub: "U123456",
|
|
259
|
+
aud: "1234567890",
|
|
260
|
+
exp: 1001, // Future timestamp
|
|
261
|
+
iat: 900,
|
|
262
|
+
};
|
|
263
|
+
mockJwt.decode.mockReturnValue({
|
|
264
|
+
payload,
|
|
265
|
+
});
|
|
266
|
+
const result = await service.verifyIdToken("valid-token");
|
|
267
|
+
expect(result).toBe(payload);
|
|
268
|
+
});
|
|
269
|
+
it("should reject token with wrong audience", async () => {
|
|
270
|
+
const payload = {
|
|
271
|
+
iss: "https://access.line.me",
|
|
272
|
+
sub: "U123456",
|
|
273
|
+
aud: "wrong-channel-id",
|
|
274
|
+
exp: 1001,
|
|
275
|
+
iat: 900,
|
|
276
|
+
};
|
|
277
|
+
mockJwt.decode.mockReturnValue({
|
|
278
|
+
payload,
|
|
279
|
+
});
|
|
280
|
+
await expect(service.verifyIdToken("invalid-token")).rejects.toThrow(new utils_1.MedusaError(utils_1.MedusaError.Types.INVALID_DATA, "ID token audience mismatch"));
|
|
281
|
+
});
|
|
282
|
+
it("should reject token with wrong issuer", async () => {
|
|
283
|
+
const payload = {
|
|
284
|
+
iss: "https://wrong-issuer.com",
|
|
285
|
+
sub: "U123456",
|
|
286
|
+
aud: "1234567890",
|
|
287
|
+
exp: 1001,
|
|
288
|
+
iat: 900,
|
|
289
|
+
};
|
|
290
|
+
mockJwt.decode.mockReturnValue({
|
|
291
|
+
payload,
|
|
292
|
+
});
|
|
293
|
+
await expect(service.verifyIdToken("invalid-token")).rejects.toThrow(new utils_1.MedusaError(utils_1.MedusaError.Types.INVALID_DATA, "ID token issuer mismatch"));
|
|
294
|
+
});
|
|
295
|
+
it("should reject expired token", async () => {
|
|
296
|
+
const payload = {
|
|
297
|
+
iss: "https://access.line.me",
|
|
298
|
+
sub: "U123456",
|
|
299
|
+
aud: "1234567890",
|
|
300
|
+
exp: 999, // Past timestamp
|
|
301
|
+
iat: 900,
|
|
302
|
+
};
|
|
303
|
+
mockJwt.decode.mockReturnValue({
|
|
304
|
+
payload,
|
|
305
|
+
});
|
|
306
|
+
await expect(service.verifyIdToken("expired-token")).rejects.toThrow(new utils_1.MedusaError(utils_1.MedusaError.Types.INVALID_DATA, "ID token has expired"));
|
|
307
|
+
});
|
|
308
|
+
it("should handle malformed ID token", async () => {
|
|
309
|
+
mockJwt.decode.mockReturnValue(null);
|
|
310
|
+
await expect(service.verifyIdToken("malformed-token")).rejects.toThrow(new utils_1.MedusaError(utils_1.MedusaError.Types.INVALID_DATA, "Failed to decode ID token"));
|
|
311
|
+
});
|
|
312
|
+
});
|
|
313
|
+
describe("Token Management", () => {
|
|
314
|
+
beforeEach(() => {
|
|
315
|
+
global.fetch = jest.fn();
|
|
316
|
+
});
|
|
317
|
+
describe("refreshToken", () => {
|
|
318
|
+
it("should refresh LINE access token", async () => {
|
|
319
|
+
const mockResponse = {
|
|
320
|
+
access_token: "new-access-token",
|
|
321
|
+
expires_in: 2592000,
|
|
322
|
+
refresh_token: "new-refresh-token",
|
|
323
|
+
};
|
|
324
|
+
global.fetch.mockResolvedValue({
|
|
325
|
+
ok: true,
|
|
326
|
+
json: async () => mockResponse,
|
|
327
|
+
});
|
|
328
|
+
const result = await service.refreshToken("old-refresh-token");
|
|
329
|
+
expect(result).toEqual(mockResponse);
|
|
330
|
+
expect(global.fetch).toHaveBeenCalledWith("https://api.line.me/oauth2/v2.1/token", expect.objectContaining({
|
|
331
|
+
method: "POST",
|
|
332
|
+
headers: {
|
|
333
|
+
"Content-Type": "application/x-www-form-urlencoded",
|
|
334
|
+
},
|
|
335
|
+
}));
|
|
336
|
+
});
|
|
337
|
+
it("should handle refresh token errors", async () => {
|
|
338
|
+
global.fetch.mockResolvedValue({
|
|
339
|
+
ok: false,
|
|
340
|
+
status: 401,
|
|
341
|
+
});
|
|
342
|
+
const result = await service.refreshToken("invalid-token");
|
|
343
|
+
expect(result).toBeNull();
|
|
344
|
+
expect(mockLogger.error).toHaveBeenCalled();
|
|
345
|
+
});
|
|
346
|
+
});
|
|
347
|
+
describe("revokeToken", () => {
|
|
348
|
+
it("should revoke LINE access token", async () => {
|
|
349
|
+
global.fetch.mockResolvedValue({
|
|
350
|
+
ok: true,
|
|
351
|
+
});
|
|
352
|
+
const result = await service.revokeToken("access-token");
|
|
353
|
+
expect(result).toBe(true);
|
|
354
|
+
expect(global.fetch).toHaveBeenCalledWith("https://api.line.me/oauth2/v2.1/revoke", expect.objectContaining({
|
|
355
|
+
method: "POST",
|
|
356
|
+
}));
|
|
357
|
+
});
|
|
358
|
+
it("should handle revoke token errors", async () => {
|
|
359
|
+
global.fetch.mockResolvedValue({
|
|
360
|
+
ok: false,
|
|
361
|
+
});
|
|
362
|
+
const result = await service.revokeToken("invalid-token");
|
|
363
|
+
expect(result).toBe(false);
|
|
364
|
+
});
|
|
365
|
+
});
|
|
366
|
+
});
|
|
367
|
+
describe("Customer Management", () => {
|
|
368
|
+
it("should find existing customer by LINE ID", async () => {
|
|
369
|
+
const mockCustomer = {
|
|
370
|
+
id: "cus_123",
|
|
371
|
+
email: "test@example.com",
|
|
372
|
+
metadata: { line_user_id: "U1234567890" },
|
|
373
|
+
};
|
|
374
|
+
mockCustomerService.listAndCount.mockResolvedValue([
|
|
375
|
+
[mockCustomer],
|
|
376
|
+
1,
|
|
377
|
+
]);
|
|
378
|
+
const result = await service.findCustomerByLineId("U1234567890");
|
|
379
|
+
expect(result).toEqual(mockCustomer);
|
|
380
|
+
expect(mockCustomerService.listAndCount).toHaveBeenCalledWith({
|
|
381
|
+
metadata: {
|
|
382
|
+
line_user_id: "U1234567890",
|
|
383
|
+
},
|
|
384
|
+
}, {});
|
|
385
|
+
});
|
|
386
|
+
it("should return null when customer not found", async () => {
|
|
387
|
+
mockCustomerService.listAndCount.mockResolvedValue([[], 0]);
|
|
388
|
+
const result = await service.findCustomerByLineId("U1234567890");
|
|
389
|
+
expect(result).toBeNull();
|
|
390
|
+
});
|
|
391
|
+
it("should create new customer from LINE profile", async () => {
|
|
392
|
+
const mockProfile = {
|
|
393
|
+
userId: "U1234567890",
|
|
394
|
+
displayName: "John Doe",
|
|
395
|
+
pictureUrl: "https://example.com/pic.jpg",
|
|
396
|
+
};
|
|
397
|
+
const mockIdToken = {
|
|
398
|
+
email: "john@example.com",
|
|
399
|
+
};
|
|
400
|
+
const mockCustomer = {
|
|
401
|
+
id: "cus_new",
|
|
402
|
+
email: "john@example.com",
|
|
403
|
+
first_name: "John",
|
|
404
|
+
last_name: "Doe",
|
|
405
|
+
};
|
|
406
|
+
mockCustomerService.create.mockResolvedValue(mockCustomer);
|
|
407
|
+
const result = await service.createCustomerFromLineProfile(mockProfile, mockIdToken);
|
|
408
|
+
expect(result).toEqual(mockCustomer);
|
|
409
|
+
expect(mockCustomerService.create).toHaveBeenCalledWith({
|
|
410
|
+
email: "john@example.com",
|
|
411
|
+
first_name: "John",
|
|
412
|
+
last_name: "Doe",
|
|
413
|
+
metadata: expect.objectContaining({
|
|
414
|
+
line_user_id: "U1234567890",
|
|
415
|
+
line_display_name: "John Doe",
|
|
416
|
+
line_picture_url: "https://example.com/pic.jpg",
|
|
417
|
+
created_via: "line_oauth",
|
|
418
|
+
}),
|
|
419
|
+
});
|
|
420
|
+
});
|
|
421
|
+
it("should use placeholder email when not provided", async () => {
|
|
422
|
+
const mockProfile = {
|
|
423
|
+
userId: "U1234567890",
|
|
424
|
+
displayName: "Test User",
|
|
425
|
+
};
|
|
426
|
+
const mockIdToken = {};
|
|
427
|
+
mockCustomerService.create.mockResolvedValue({
|
|
428
|
+
id: "cus_new",
|
|
429
|
+
email: "line-U1234567890@line.local",
|
|
430
|
+
});
|
|
431
|
+
await service.createCustomerFromLineProfile(mockProfile, mockIdToken);
|
|
432
|
+
expect(mockCustomerService.create).toHaveBeenCalledWith(expect.objectContaining({
|
|
433
|
+
email: "line-U1234567890@line.local",
|
|
434
|
+
}));
|
|
435
|
+
});
|
|
436
|
+
});
|
|
437
|
+
});
|
|
438
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2VydmljZS50ZXN0LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vc3JjL3Byb3ZpZGVycy9saW5lL19fdGVzdHNfXy9zZXJ2aWNlLnRlc3QudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7QUFBQSx5REFBNkM7QUFDN0MscURBQXdEO0FBQ3hELGdFQUErQjtBQUMvQixvREFBNEI7QUFFNUIsb0JBQW9CO0FBQ3BCLElBQUksQ0FBQyxJQUFJLENBQUMsY0FBYyxDQUFDLENBQUM7QUFDMUIsSUFBSSxDQUFDLElBQUksQ0FBQyxRQUFRLENBQUMsQ0FBQztBQUVwQixzQkFBc0I7QUFDdEIsTUFBTSxDQUFDLEtBQUssR0FBRyxJQUFJLENBQUMsRUFBRSxFQUFFLENBQUM7QUFFekIsUUFBUSxDQUFDLHFCQUFxQixFQUFFLEdBQUcsRUFBRTtJQUNuQyxJQUFJLE9BQTRCLENBQUM7SUFDakMsSUFBSSxVQUFlLENBQUM7SUFDcEIsSUFBSSxtQkFBd0IsQ0FBQztJQUM3QixJQUFJLHVCQUE0QixDQUFDO0lBQ2pDLElBQUksU0FBNEMsQ0FBQztJQUNqRCxJQUFJLFVBQXNDLENBQUM7SUFDM0MsSUFBSSxPQUFnQyxDQUFDO0lBRXJDLE1BQU0sY0FBYyxHQUFHO1FBQ3JCLGFBQWEsRUFBRSxZQUFZO1FBQzNCLGlCQUFpQixFQUFFLGFBQWE7UUFDaEMsZUFBZSxFQUFFLDhCQUE4QjtRQUMvQyxrQkFBa0IsRUFBRSxJQUFJO1FBQ3hCLGVBQWUsRUFBRSxJQUFJO0tBQ3RCLENBQUM7SUFFRixVQUFVLENBQUMsR0FBRyxFQUFFO1FBQ2QsSUFBSSxDQUFDLGFBQWEsRUFBRSxDQUFDO1FBQ3JCLFNBQVMsR0FBRyxNQUFNLENBQUMsS0FBMEMsQ0FBQztRQUM5RCxVQUFVLEdBQUcsZ0JBQW9DLENBQUM7UUFDbEQsT0FBTyxHQUFHLHNCQUE4QixDQUFDO1FBRXpDLFVBQVUsR0FBRztZQUNYLElBQUksRUFBRSxJQUFJLENBQUMsRUFBRSxF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
|