@khanacademy/wonder-blocks-testing 0.0.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.
@@ -0,0 +1,100 @@
1
+ // @flow
2
+ import * as WonderStuffCoreModule from "@khanacademy/wonder-stuff-core";
3
+
4
+ import {combineTopLevel} from "../combine-top-level.js";
5
+
6
+ jest.mock("@khanacademy/wonder-stuff-core");
7
+
8
+ describe("#combine", () => {
9
+ beforeEach(() => {
10
+ jest.resetAllMocks();
11
+ });
12
+
13
+ it.each([undefined, null, 42, "test", true])(
14
+ "should return a clone of val2 if val1 is %s",
15
+ (val1) => {
16
+ // Arrange
17
+ jest.spyOn(WonderStuffCoreModule, "clone").mockImplementation(
18
+ (v) => `CLONED: ${v}`,
19
+ );
20
+ const val2 = "VALUE2";
21
+
22
+ // Act
23
+ const result = combineTopLevel(val1, val2);
24
+
25
+ // Assert
26
+ expect(result).toEqual(`CLONED: VALUE2`);
27
+ },
28
+ );
29
+
30
+ it("should return a deduplicated array including values from val1 and val2, with val2 values first if both are arrays", () => {
31
+ // Arrange
32
+ jest.spyOn(WonderStuffCoreModule, "clone").mockImplementation((v) => v);
33
+ const val1 = ["VALUE1", "VALUE2", "VALUE2"];
34
+ const val2 = ["VALUE2", "VALUE3", "VALUE3"];
35
+
36
+ // Act
37
+ const result = combineTopLevel(val1, val2);
38
+
39
+ // Assert
40
+ expect(result).toEqual(["VALUE1", "VALUE2", "VALUE3"]);
41
+ });
42
+
43
+ it("should return a clone of val2 if val2 is an array but val1 is not", () => {
44
+ // Arrange
45
+ jest.spyOn(WonderStuffCoreModule, "clone").mockImplementation(
46
+ (v) => `CLONED: ${v}`,
47
+ );
48
+ const val1 = "VALUE1";
49
+ const val2 = ["VALUE1", "VALUE2", "VALUE3"];
50
+
51
+ // Act
52
+ const result = combineTopLevel(val1, val2);
53
+
54
+ // Assert
55
+ expect(result).toEqual("CLONED: VALUE1,VALUE2,VALUE3");
56
+ });
57
+
58
+ it("should return a clone of val2 if val2 is not an array but val1 is", () => {
59
+ // Arrange
60
+ jest.spyOn(WonderStuffCoreModule, "clone").mockImplementation(
61
+ (v) => `CLONED: ${JSON.stringify(v)}`,
62
+ );
63
+ const val1 = ["VALUE1", "VALUE2", "VALUE3"];
64
+ const val2 = {
65
+ key1: "VALUE1",
66
+ };
67
+
68
+ // Act
69
+ const result = combineTopLevel(val1, val2);
70
+
71
+ // Assert
72
+ expect(result).toEqual('CLONED: {"key1":"VALUE1"}');
73
+ });
74
+
75
+ it("should return a combination of val1 and val2 (cloned) properties with val2 overriding val1 when both are non-array objects", () => {
76
+ // Arrange
77
+ jest.spyOn(WonderStuffCoreModule, "clone").mockImplementation((v) => v);
78
+ const val1 = {
79
+ a: "val1_VALUE1",
80
+ b: "val1_VALUE2",
81
+ c: "val1_VALUE3",
82
+ };
83
+ const val2 = {
84
+ b: "val2_VALUE2",
85
+ c: "val2_VALUE3",
86
+ d: "val2_VALUE4",
87
+ };
88
+
89
+ // Act
90
+ const result = combineTopLevel(val1, val2);
91
+
92
+ // Assert
93
+ expect(result).toEqual({
94
+ a: "val1_VALUE1",
95
+ b: "val2_VALUE2",
96
+ c: "val2_VALUE3",
97
+ d: "val2_VALUE4",
98
+ });
99
+ });
100
+ });
@@ -0,0 +1,483 @@
1
+ // @flow
2
+ import * as SetupModule from "../setup.js";
3
+ import * as CombineOptionsModule from "../combine-options.js";
4
+ import {fixtures} from "../fixtures.js";
5
+
6
+ jest.mock("../setup.js");
7
+ jest.mock("../combine-options.js");
8
+
9
+ describe("#fixtures", () => {
10
+ beforeEach(() => {
11
+ jest.clearAllMocks();
12
+ });
13
+
14
+ it("should declare a group on the configured adapter with the given title and description", () => {
15
+ // Arrange
16
+ const fakeGroup = {
17
+ closeGroup: jest.fn(),
18
+ };
19
+ const adapter = {
20
+ declareGroup: jest.fn().mockReturnValue(fakeGroup),
21
+ name: "testadapter",
22
+ };
23
+ jest.spyOn(SetupModule, "getConfiguration").mockReturnValue({
24
+ adapter,
25
+ });
26
+
27
+ // Act
28
+ fixtures(
29
+ {
30
+ title: "TITLE",
31
+ description: "DESCRIPTION",
32
+ component: () => "COMPONENT",
33
+ },
34
+ jest.fn(),
35
+ );
36
+
37
+ // Assert
38
+ expect(adapter.declareGroup).toHaveBeenCalledWith({
39
+ title: "TITLE",
40
+ description: "DESCRIPTION",
41
+ });
42
+ });
43
+
44
+ it("should default the title to the component.displayName in the absence of title", () => {
45
+ // Arrange
46
+ const fakeGroup = {
47
+ closeGroup: jest.fn(),
48
+ };
49
+ const adapter = {
50
+ declareGroup: jest.fn().mockReturnValue(fakeGroup),
51
+ name: "testadapter",
52
+ };
53
+ jest.spyOn(SetupModule, "getConfiguration").mockReturnValue({
54
+ adapter,
55
+ });
56
+ const component = () => "COMPONENT";
57
+ component.displayName = "DISPLAYNAME";
58
+
59
+ // Act
60
+ fixtures(
61
+ {
62
+ component,
63
+ },
64
+ jest.fn(),
65
+ );
66
+
67
+ // Assert
68
+ expect(adapter.declareGroup).toHaveBeenCalledWith({
69
+ title: "DISPLAYNAME",
70
+ });
71
+ });
72
+
73
+ it("should default the title to the component.name in the absence of component.displayName", () => {
74
+ // Arrange
75
+ const fakeGroup = {
76
+ closeGroup: jest.fn(),
77
+ };
78
+ const adapter = {
79
+ declareGroup: jest.fn().mockReturnValue(fakeGroup),
80
+ name: "testadapter",
81
+ };
82
+ jest.spyOn(SetupModule, "getConfiguration").mockReturnValue({
83
+ adapter,
84
+ });
85
+ const component = function FUNCTIONNAME() {
86
+ return "COMPONENT";
87
+ };
88
+
89
+ // Act
90
+ fixtures(
91
+ {
92
+ component,
93
+ },
94
+ jest.fn(),
95
+ );
96
+
97
+ // Assert
98
+ expect(adapter.declareGroup).toHaveBeenCalledWith({
99
+ title: "FUNCTIONNAME",
100
+ });
101
+ });
102
+
103
+ it("should default the title to 'Component' in the absence of component.name", () => {
104
+ // Arrange
105
+ const fakeGroup = {
106
+ closeGroup: jest.fn(),
107
+ };
108
+ const adapter = {
109
+ declareGroup: jest.fn().mockReturnValue(fakeGroup),
110
+ name: "testadapter",
111
+ };
112
+ jest.spyOn(SetupModule, "getConfiguration").mockReturnValue({
113
+ adapter,
114
+ });
115
+
116
+ // Act
117
+ fixtures(
118
+ {
119
+ component: ({}: any),
120
+ },
121
+ jest.fn(),
122
+ );
123
+
124
+ // Assert
125
+ expect(adapter.declareGroup).toHaveBeenCalledWith({
126
+ title: "Component",
127
+ });
128
+ });
129
+
130
+ it("should invoke the passed fn with function argument", () => {
131
+ // Arrange
132
+ const fakeGroup = {
133
+ declareFixture: jest.fn(),
134
+ closeGroup: jest.fn(),
135
+ };
136
+ const adapter = {
137
+ declareGroup: jest.fn().mockReturnValue(fakeGroup),
138
+ name: "testadapter",
139
+ };
140
+ jest.spyOn(SetupModule, "getConfiguration").mockReturnValue({
141
+ adapter,
142
+ });
143
+ const fn = jest.fn();
144
+
145
+ // Act
146
+ fixtures(
147
+ {
148
+ title: "GROUP_TITLE",
149
+ description: "GROUP_DESCRIPTION",
150
+ component: () => "COMPONENT",
151
+ },
152
+ fn,
153
+ );
154
+
155
+ // Assert
156
+ expect(fn).toHaveBeenCalledWith(expect.any(Function));
157
+ });
158
+
159
+ it("should combine additionalAdapterOptions for the appropriate adapter with defaultAdapterOptions", () => {
160
+ // Arrange
161
+ const combineOptionsSpy = jest.spyOn(
162
+ CombineOptionsModule,
163
+ "combineOptions",
164
+ );
165
+ const fakeGroup = {
166
+ declareFixture: jest.fn(),
167
+ closeGroup: jest.fn(),
168
+ };
169
+ const adapter = {
170
+ declareGroup: jest.fn().mockReturnValue(fakeGroup),
171
+ name: "testadapter",
172
+ };
173
+ const defaultAdapterOptions = {
174
+ foo: "bar",
175
+ };
176
+ jest.spyOn(SetupModule, "getConfiguration").mockReturnValue({
177
+ adapter,
178
+ defaultAdapterOptions,
179
+ });
180
+ const additionalTestAdapterOptions = {
181
+ bim: "bop",
182
+ };
183
+
184
+ // Act
185
+ fixtures(
186
+ {
187
+ component: () => "COMPONENT",
188
+ additionalAdapterOptions: {
189
+ testadapter: additionalTestAdapterOptions,
190
+ otheradapterwedontcareabout: {
191
+ fig: "fug",
192
+ },
193
+ },
194
+ },
195
+ jest.fn(),
196
+ );
197
+
198
+ // Assert
199
+ expect(combineOptionsSpy).toHaveBeenCalledWith(
200
+ defaultAdapterOptions,
201
+ additionalTestAdapterOptions,
202
+ );
203
+ });
204
+
205
+ it("should call group.closeGroup with the combined adapter options", () => {
206
+ // Arrange
207
+ jest.spyOn(CombineOptionsModule, "combineOptions").mockReturnValue(
208
+ "COMBINED_OPTIONS",
209
+ );
210
+ const fakeGroup = {
211
+ declareFixture: jest.fn(),
212
+ closeGroup: jest.fn(),
213
+ };
214
+ const adapter = {
215
+ declareGroup: jest.fn().mockReturnValue(fakeGroup),
216
+ name: "testadapter",
217
+ };
218
+ const defaultAdapterOptions = {
219
+ foo: "bar",
220
+ };
221
+ jest.spyOn(SetupModule, "getConfiguration").mockReturnValue({
222
+ adapter,
223
+ defaultAdapterOptions,
224
+ });
225
+ const additionalTestAdapterOptions = {
226
+ bim: "bop",
227
+ };
228
+
229
+ // Act
230
+ fixtures(
231
+ {
232
+ component: () => "COMPONENT",
233
+ additionalAdapterOptions: {
234
+ testadapter: additionalTestAdapterOptions,
235
+ otheradapterwedontcareabout: {
236
+ fig: "fug",
237
+ },
238
+ },
239
+ },
240
+ jest.fn(),
241
+ );
242
+
243
+ // Assert
244
+ expect(fakeGroup.closeGroup).toHaveBeenCalledWith("COMBINED_OPTIONS");
245
+ });
246
+
247
+ it("should return the result of group.closeGroup", () => {
248
+ // Arrange
249
+ const fakeGroup = {
250
+ declareFixture: jest.fn(),
251
+ closeGroup: jest.fn().mockReturnValue("RESULT"),
252
+ };
253
+ const adapter = {
254
+ declareGroup: jest.fn().mockReturnValue(fakeGroup),
255
+ name: "testadapter",
256
+ };
257
+ jest.spyOn(SetupModule, "getConfiguration").mockReturnValue({
258
+ adapter,
259
+ });
260
+
261
+ // Act
262
+ const result = fixtures(
263
+ {
264
+ component: () => "COMPONENT",
265
+ },
266
+ jest.fn(),
267
+ );
268
+
269
+ // Assert
270
+ expect(result).toEqual("RESULT");
271
+ });
272
+
273
+ describe("injected fixture fn", () => {
274
+ it("should call group.declareFixture with description and props getter", () => {
275
+ // Arrange
276
+ const fakeGroup = {
277
+ declareFixture: jest.fn(),
278
+ closeGroup: jest.fn(),
279
+ };
280
+ const adapter = {
281
+ declareGroup: jest.fn().mockReturnValue(fakeGroup),
282
+ name: "testadapter",
283
+ };
284
+ jest.spyOn(SetupModule, "getConfiguration").mockReturnValue({
285
+ adapter,
286
+ });
287
+ const component = () => "COMPONENT";
288
+
289
+ // Act
290
+ fixtures(
291
+ {
292
+ title: "GROUP_TITLE",
293
+ description: "GROUP_DESCRIPTION",
294
+ component,
295
+ },
296
+ (fixture) => {
297
+ fixture("FIXTURE_DESCRIPTION", {these: "areProps"});
298
+ },
299
+ );
300
+
301
+ // Assert
302
+ expect(fakeGroup.declareFixture).toHaveBeenCalledWith({
303
+ description: "FIXTURE_DESCRIPTION",
304
+ getProps: expect.any(Function),
305
+ component,
306
+ });
307
+ });
308
+
309
+ it("should pass wrapper component to group.declareFixture", () => {
310
+ // Arrange
311
+ const fakeGroup = {
312
+ declareFixture: jest.fn(),
313
+ closeGroup: jest.fn(),
314
+ };
315
+ const adapter = {
316
+ declareGroup: jest.fn().mockReturnValue(fakeGroup),
317
+ name: "testadapter",
318
+ };
319
+ jest.spyOn(SetupModule, "getConfiguration").mockReturnValue({
320
+ adapter,
321
+ });
322
+ const defaultWrapper = () => "DEFAULT_WRAPPER";
323
+ const wrapper = () => "WRAPPER";
324
+
325
+ // Act
326
+ fixtures(
327
+ {
328
+ title: "GROUP_TITLE",
329
+ description: "GROUP_DESCRIPTION",
330
+ component: () => "COMPONENT",
331
+ defaultWrapper,
332
+ },
333
+ (fixture) => {
334
+ fixture(
335
+ "FIXTURE_DESCRIPTION",
336
+ {these: "areProps"},
337
+ wrapper,
338
+ );
339
+ },
340
+ );
341
+
342
+ // Assert
343
+ expect(fakeGroup.declareFixture).toHaveBeenCalledWith({
344
+ description: "FIXTURE_DESCRIPTION",
345
+ getProps: expect.any(Function),
346
+ component: wrapper,
347
+ });
348
+ });
349
+
350
+ it("should pass defaultWrapper component to group.declareFixture if no wrapper", () => {
351
+ // Arrange
352
+ const fakeGroup = {
353
+ declareFixture: jest.fn(),
354
+ closeGroup: jest.fn(),
355
+ };
356
+ const adapter = {
357
+ declareGroup: jest.fn().mockReturnValue(fakeGroup),
358
+ name: "testadapter",
359
+ };
360
+ jest.spyOn(SetupModule, "getConfiguration").mockReturnValue({
361
+ adapter,
362
+ });
363
+ const defaultWrapper = () => "DEFAULT_WRAPPER";
364
+
365
+ // Act
366
+ fixtures(
367
+ {
368
+ title: "GROUP_TITLE",
369
+ description: "GROUP_DESCRIPTION",
370
+ component: () => "COMPONENT",
371
+ defaultWrapper,
372
+ },
373
+ (fixture) => {
374
+ fixture("FIXTURE_DESCRIPTION", {these: "areProps"});
375
+ },
376
+ );
377
+
378
+ // Assert
379
+ expect(fakeGroup.declareFixture).toHaveBeenCalledWith({
380
+ description: "FIXTURE_DESCRIPTION",
381
+ getProps: expect.any(Function),
382
+ component: defaultWrapper,
383
+ });
384
+ });
385
+
386
+ describe("getProps fn passed to group.declareFixture", () => {
387
+ it("should return the props when props is an object", () => {
388
+ // Arrange
389
+ const fakeGroup = {
390
+ declareFixture: jest.fn(),
391
+ closeGroup: jest.fn(),
392
+ };
393
+ const adapter = {
394
+ declareGroup: jest.fn().mockReturnValue(fakeGroup),
395
+ name: "testadapter",
396
+ };
397
+ jest.spyOn(SetupModule, "getConfiguration").mockReturnValue({
398
+ adapter,
399
+ });
400
+
401
+ // Act
402
+ fixtures(
403
+ {
404
+ component: () => "COMPONENT",
405
+ },
406
+ (fixture) => {
407
+ fixture("FIXTURE_DESCRIPTION", {these: "areProps"});
408
+ },
409
+ );
410
+ const getPropsFn =
411
+ fakeGroup.declareFixture.mock.calls[0][0].getProps;
412
+ const result = getPropsFn("OPTIONS");
413
+
414
+ // Assert
415
+ expect(result).toEqual({these: "areProps"});
416
+ });
417
+
418
+ it("should invoke the props function with given options when props is a function", () => {
419
+ // Arrange
420
+ const fakeGroup = {
421
+ declareFixture: jest.fn(),
422
+ closeGroup: jest.fn(),
423
+ };
424
+ const adapter = {
425
+ declareGroup: jest.fn().mockReturnValue(fakeGroup),
426
+ name: "testadapter",
427
+ };
428
+ jest.spyOn(SetupModule, "getConfiguration").mockReturnValue({
429
+ adapter,
430
+ });
431
+ const props = jest.fn().mockReturnValue({these: "areProps"});
432
+
433
+ // Act
434
+ fixtures(
435
+ {
436
+ component: () => "COMPONENT",
437
+ },
438
+ (fixture) => {
439
+ fixture("FIXTURE_DESCRIPTION", props);
440
+ },
441
+ );
442
+ const getPropsFn =
443
+ fakeGroup.declareFixture.mock.calls[0][0].getProps;
444
+ getPropsFn("OPTIONS");
445
+
446
+ // Assert
447
+ expect(props).toHaveBeenCalledWith("OPTIONS");
448
+ });
449
+
450
+ it("should return the result of the props function when props is a function", () => {
451
+ // Arrange
452
+ const fakeGroup = {
453
+ declareFixture: jest.fn(),
454
+ closeGroup: jest.fn(),
455
+ };
456
+ const adapter = {
457
+ declareGroup: jest.fn().mockReturnValue(fakeGroup),
458
+ name: "testadapter",
459
+ };
460
+ jest.spyOn(SetupModule, "getConfiguration").mockReturnValue({
461
+ adapter,
462
+ });
463
+ const props = jest.fn().mockReturnValue({these: "areProps"});
464
+
465
+ // Act
466
+ fixtures(
467
+ {
468
+ component: () => "COMPONENT",
469
+ },
470
+ (fixture) => {
471
+ fixture("FIXTURE_DESCRIPTION", props);
472
+ },
473
+ );
474
+ const getPropsFn =
475
+ fakeGroup.declareFixture.mock.calls[0][0].getProps;
476
+ const result = getPropsFn("OPTIONS");
477
+
478
+ // Assert
479
+ expect(result).toEqual({these: "areProps"});
480
+ });
481
+ });
482
+ });
483
+ });
@@ -0,0 +1,69 @@
1
+ // @flow
2
+ import {isolateModules} from "../../jest/isolate-modules.js";
3
+
4
+ describe("#getConfiguration", () => {
5
+ it("should return the configuration passed during setup", () => {
6
+ // Arrange
7
+ const {setup, getConfiguration} = isolateModules(() =>
8
+ require("../setup.js"),
9
+ );
10
+ const configuration = {
11
+ adapter: {
12
+ name: "mytestadapter",
13
+ declareGroup: jest.fn(),
14
+ },
15
+ defaultAdapterOptions: {},
16
+ };
17
+ setup(configuration);
18
+
19
+ // Act
20
+ const result = getConfiguration();
21
+
22
+ // Assert
23
+ expect(result).toBe(configuration);
24
+ });
25
+
26
+ it("should throw if setup has not been performed", () => {
27
+ // Arrange
28
+ const {getConfiguration} = isolateModules(() => require("../setup.js"));
29
+
30
+ // Act
31
+ const underTest = () => getConfiguration();
32
+
33
+ // Assert
34
+ expect(underTest).toThrowErrorMatchingInlineSnapshot(
35
+ `"Not configured"`,
36
+ );
37
+ });
38
+ });
39
+
40
+ describe("#setup", () => {
41
+ it("should set the configuration returned by getConfiguration", () => {
42
+ // Arrange
43
+ const {setup, getConfiguration} = isolateModules(() =>
44
+ require("../setup.js"),
45
+ );
46
+ const configuration1 = {
47
+ adapter: {
48
+ name: "mytestadapter1",
49
+ declareGroup: jest.fn(),
50
+ },
51
+ defaultAdapterOptions: {},
52
+ };
53
+ const configuration2 = {
54
+ adapter: {
55
+ name: "mytestadapter2",
56
+ declareGroup: jest.fn(),
57
+ },
58
+ defaultAdapterOptions: {},
59
+ };
60
+
61
+ // Act
62
+ setup(configuration1);
63
+ setup(configuration2);
64
+ const result = getConfiguration();
65
+
66
+ // Assert
67
+ expect(result).toBe(configuration2);
68
+ });
69
+ });
@@ -0,0 +1,9 @@
1
+ // Jest Snapshot v1, https://goo.gl/fbAQLP
2
+
3
+ exports[`AdapterGroup #constructor should throw if options are not valid (a string) 1`] = `"options must be an object"`;
4
+
5
+ exports[`AdapterGroup #constructor should throw if options are not valid (null) 1`] = `"options must be an object"`;
6
+
7
+ exports[`AdapterGroup #declareFixture should throw if options are not valid (a string) 1`] = `"options must be an object"`;
8
+
9
+ exports[`AdapterGroup #declareFixture should throw if options are not valid (null) 1`] = `"options must be an object"`;
@@ -0,0 +1,13 @@
1
+ // Jest Snapshot v1, https://goo.gl/fbAQLP
2
+
3
+ exports[`Adapter #constructor should throw if closeGroupFn is invalid 1`] = `"closeGroupFn must be a function"`;
4
+
5
+ exports[`Adapter #constructor should throw if closeGroupFn is invalid 2`] = `"closeGroupFn must be a function"`;
6
+
7
+ exports[`Adapter #constructor should throw if the name is invalid ( ) 1`] = `"name must be a non-empty string"`;
8
+
9
+ exports[`Adapter #constructor should throw if the name is invalid () 1`] = `"name must be a non-empty string"`;
10
+
11
+ exports[`Adapter #constructor should throw if the name is invalid (8) 1`] = `"name must be a string"`;
12
+
13
+ exports[`Adapter #constructor should throw if the name is invalid (null) 1`] = `"name must be a string"`;