@org-press/deploy-github-pages 0.9.12

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,759 @@
1
+ /**
2
+ * GitHub Pages Adapter tests
3
+ */
4
+
5
+ import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
6
+ import * as childProcess from "node:child_process";
7
+ import * as fs from "node:fs";
8
+ import { GitHubPagesAdapter, githubPagesAdapter } from "./adapter.ts";
9
+ import type {
10
+ DeployContext,
11
+ AdapterConfig,
12
+ PackageMetadata,
13
+ DeployLogger,
14
+ } from "@org-press/deploy";
15
+
16
+ // Mock child_process
17
+ vi.mock("node:child_process", () => ({
18
+ spawnSync: vi.fn(),
19
+ }));
20
+
21
+ // Mock fs
22
+ vi.mock("node:fs", () => ({
23
+ writeFileSync: vi.fn(),
24
+ existsSync: vi.fn(),
25
+ rmSync: vi.fn(),
26
+ mkdirSync: vi.fn(),
27
+ }));
28
+
29
+ describe("GitHubPagesAdapter", () => {
30
+ beforeEach(() => {
31
+ vi.clearAllMocks();
32
+ });
33
+
34
+ describe("constructor", () => {
35
+ it("should create adapter with default options", () => {
36
+ const adapter = new GitHubPagesAdapter();
37
+ expect(adapter.name).toBe("github-pages");
38
+ expect(adapter.description).toBe("Deploy to GitHub Pages");
39
+ });
40
+
41
+ it("should accept custom config", () => {
42
+ const adapter = new GitHubPagesAdapter({
43
+ repo: "user/repo",
44
+ branch: "main",
45
+ cname: "example.com",
46
+ noJekyll: false,
47
+ message: "Custom deploy message",
48
+ });
49
+ expect(adapter.name).toBe("github-pages");
50
+ });
51
+ });
52
+
53
+ describe("validate", () => {
54
+ it("should validate successfully when git is available", async () => {
55
+ vi.mocked(childProcess.spawnSync).mockReturnValue({
56
+ status: 0,
57
+ stdout: "git version 2.40.0",
58
+ stderr: "",
59
+ pid: 123,
60
+ output: [],
61
+ signal: null,
62
+ });
63
+
64
+ const adapter = new GitHubPagesAdapter({ repo: "user/repo" });
65
+ const config: AdapterConfig = {
66
+ options: {},
67
+ env: {},
68
+ };
69
+
70
+ const result = await adapter.validate(config);
71
+
72
+ expect(result.valid).toBe(true);
73
+ expect(result.errors).toEqual([]);
74
+ });
75
+
76
+ it("should fail if git is not available", async () => {
77
+ vi.mocked(childProcess.spawnSync).mockReturnValue({
78
+ status: 1,
79
+ stdout: "",
80
+ stderr: "git not found",
81
+ pid: 123,
82
+ output: [],
83
+ signal: null,
84
+ });
85
+
86
+ const adapter = new GitHubPagesAdapter();
87
+ const config: AdapterConfig = {
88
+ options: {},
89
+ env: {},
90
+ };
91
+
92
+ const result = await adapter.validate(config);
93
+
94
+ expect(result.valid).toBe(false);
95
+ expect(result.errors).toContain("git is not available in PATH");
96
+ });
97
+
98
+ it("should fail with invalid repository format", async () => {
99
+ vi.mocked(childProcess.spawnSync).mockReturnValue({
100
+ status: 0,
101
+ stdout: "git version 2.40.0",
102
+ stderr: "",
103
+ pid: 123,
104
+ output: [],
105
+ signal: null,
106
+ });
107
+
108
+ const adapter = new GitHubPagesAdapter();
109
+ const config: AdapterConfig = {
110
+ options: { repo: "invalid-repo-format" },
111
+ env: {},
112
+ };
113
+
114
+ const result = await adapter.validate(config);
115
+
116
+ expect(result.valid).toBe(false);
117
+ expect(
118
+ result.errors.some((e) => e.includes("Invalid repository format"))
119
+ ).toBe(true);
120
+ });
121
+
122
+ it("should accept valid repository formats", async () => {
123
+ vi.mocked(childProcess.spawnSync).mockReturnValue({
124
+ status: 0,
125
+ stdout: "git version 2.40.0",
126
+ stderr: "",
127
+ pid: 123,
128
+ output: [],
129
+ signal: null,
130
+ });
131
+
132
+ const testCases = [
133
+ "user/repo",
134
+ "org/my-repo",
135
+ "User123/Repo.Name",
136
+ "org-name/repo_name",
137
+ ];
138
+
139
+ for (const repo of testCases) {
140
+ const adapter = new GitHubPagesAdapter({ repo });
141
+ const config: AdapterConfig = {
142
+ options: {},
143
+ env: {},
144
+ };
145
+
146
+ const result = await adapter.validate(config);
147
+ expect(result.valid).toBe(true);
148
+ expect(result.errors).toEqual([]);
149
+ }
150
+ });
151
+
152
+ it("should fail with invalid branch name", async () => {
153
+ vi.mocked(childProcess.spawnSync).mockReturnValue({
154
+ status: 0,
155
+ stdout: "git version 2.40.0",
156
+ stderr: "",
157
+ pid: 123,
158
+ output: [],
159
+ signal: null,
160
+ });
161
+
162
+ const adapter = new GitHubPagesAdapter();
163
+ const config: AdapterConfig = {
164
+ options: { repo: "user/repo", branch: "invalid branch!" },
165
+ env: {},
166
+ };
167
+
168
+ const result = await adapter.validate(config);
169
+
170
+ expect(result.valid).toBe(false);
171
+ expect(result.errors.some((e) => e.includes("Invalid branch name"))).toBe(
172
+ true
173
+ );
174
+ });
175
+
176
+ it("should warn when no repo specified", async () => {
177
+ vi.mocked(childProcess.spawnSync).mockReturnValue({
178
+ status: 0,
179
+ stdout: "git version 2.40.0",
180
+ stderr: "",
181
+ pid: 123,
182
+ output: [],
183
+ signal: null,
184
+ });
185
+
186
+ const adapter = new GitHubPagesAdapter();
187
+ const config: AdapterConfig = {
188
+ options: {},
189
+ env: {},
190
+ };
191
+
192
+ const result = await adapter.validate(config);
193
+
194
+ expect(result.valid).toBe(true);
195
+ expect(result.warnings.some((w) => w.includes("auto-detect"))).toBe(true);
196
+ });
197
+ });
198
+
199
+ describe("deploy", () => {
200
+ const createLogger = (): DeployLogger & { logs: string[] } => {
201
+ const logs: string[] = [];
202
+ return {
203
+ logs,
204
+ info: (msg) => logs.push(`INFO: ${msg}`),
205
+ warn: (msg) => logs.push(`WARN: ${msg}`),
206
+ error: (msg) => logs.push(`ERROR: ${msg}`),
207
+ debug: (msg) => logs.push(`DEBUG: ${msg}`),
208
+ };
209
+ };
210
+
211
+ const createContext = (
212
+ overrides: Partial<DeployContext> = {}
213
+ ): DeployContext => {
214
+ const metadata: PackageMetadata = {
215
+ name: "test-site",
216
+ version: "1.0.0",
217
+ description: "Test site",
218
+ };
219
+
220
+ return {
221
+ outDir: "/tmp/test-deploy",
222
+ metadata,
223
+ adapterConfig: {},
224
+ environment: "production",
225
+ dryRun: false,
226
+ logger: createLogger(),
227
+ ...overrides,
228
+ };
229
+ };
230
+
231
+ it("should return success for dry run without executing git commands", async () => {
232
+ const adapter = new GitHubPagesAdapter({ repo: "user/my-site" });
233
+ const context = createContext({ dryRun: true });
234
+
235
+ const result = await adapter.deploy(context);
236
+
237
+ expect(result.success).toBe(true);
238
+ expect(result.deploymentId).toContain("dry-run-");
239
+ expect(result.url).toBe("https://user.github.io/my-site");
240
+ // Git commands should not be called in dry run (except for auto-detect if no repo)
241
+ expect(fs.writeFileSync).not.toHaveBeenCalled();
242
+ });
243
+
244
+ it("should create .nojekyll file by default", async () => {
245
+ // Mock all git commands to succeed
246
+ vi.mocked(childProcess.spawnSync).mockReturnValue({
247
+ status: 0,
248
+ stdout: "",
249
+ stderr: "",
250
+ pid: 123,
251
+ output: [],
252
+ signal: null,
253
+ });
254
+
255
+ vi.mocked(fs.existsSync).mockReturnValue(false);
256
+
257
+ const adapter = new GitHubPagesAdapter({ repo: "user/my-site" });
258
+ const context = createContext();
259
+
260
+ await adapter.deploy(context);
261
+
262
+ expect(fs.writeFileSync).toHaveBeenCalledWith(
263
+ "/tmp/test-deploy/.nojekyll",
264
+ ""
265
+ );
266
+ });
267
+
268
+ it("should not create .nojekyll file when noJekyll is false", async () => {
269
+ vi.mocked(childProcess.spawnSync).mockReturnValue({
270
+ status: 0,
271
+ stdout: "",
272
+ stderr: "",
273
+ pid: 123,
274
+ output: [],
275
+ signal: null,
276
+ });
277
+
278
+ vi.mocked(fs.existsSync).mockReturnValue(false);
279
+
280
+ const adapter = new GitHubPagesAdapter({
281
+ repo: "user/my-site",
282
+ noJekyll: false,
283
+ });
284
+ const context = createContext();
285
+
286
+ await adapter.deploy(context);
287
+
288
+ expect(fs.writeFileSync).not.toHaveBeenCalledWith(
289
+ "/tmp/test-deploy/.nojekyll",
290
+ ""
291
+ );
292
+ });
293
+
294
+ it("should create CNAME file when cname is specified", async () => {
295
+ vi.mocked(childProcess.spawnSync).mockReturnValue({
296
+ status: 0,
297
+ stdout: "",
298
+ stderr: "",
299
+ pid: 123,
300
+ output: [],
301
+ signal: null,
302
+ });
303
+
304
+ vi.mocked(fs.existsSync).mockReturnValue(false);
305
+
306
+ const adapter = new GitHubPagesAdapter({
307
+ repo: "user/my-site",
308
+ cname: "example.com",
309
+ });
310
+ const context = createContext();
311
+
312
+ await adapter.deploy(context);
313
+
314
+ expect(fs.writeFileSync).toHaveBeenCalledWith(
315
+ "/tmp/test-deploy/CNAME",
316
+ "example.com"
317
+ );
318
+ });
319
+
320
+ it("should return custom domain URL when cname is specified", async () => {
321
+ vi.mocked(childProcess.spawnSync).mockReturnValue({
322
+ status: 0,
323
+ stdout: "",
324
+ stderr: "",
325
+ pid: 123,
326
+ output: [],
327
+ signal: null,
328
+ });
329
+
330
+ vi.mocked(fs.existsSync).mockReturnValue(false);
331
+
332
+ const adapter = new GitHubPagesAdapter({
333
+ repo: "user/my-site",
334
+ cname: "example.com",
335
+ });
336
+ const context = createContext();
337
+
338
+ const result = await adapter.deploy(context);
339
+
340
+ expect(result.success).toBe(true);
341
+ expect(result.url).toBe("https://example.com");
342
+ });
343
+
344
+ it("should remove existing .git directory", async () => {
345
+ vi.mocked(childProcess.spawnSync).mockReturnValue({
346
+ status: 0,
347
+ stdout: "",
348
+ stderr: "",
349
+ pid: 123,
350
+ output: [],
351
+ signal: null,
352
+ });
353
+
354
+ vi.mocked(fs.existsSync).mockReturnValue(true);
355
+
356
+ const adapter = new GitHubPagesAdapter({ repo: "user/my-site" });
357
+ const context = createContext();
358
+
359
+ await adapter.deploy(context);
360
+
361
+ expect(fs.rmSync).toHaveBeenCalledWith("/tmp/test-deploy/.git", {
362
+ recursive: true,
363
+ });
364
+ });
365
+
366
+ it("should initialize git repository and push to gh-pages branch", async () => {
367
+ const gitCalls: string[][] = [];
368
+ vi.mocked(childProcess.spawnSync).mockImplementation((cmd, args) => {
369
+ if (cmd === "git") {
370
+ gitCalls.push(args as string[]);
371
+ }
372
+ return {
373
+ status: 0,
374
+ stdout: "",
375
+ stderr: "",
376
+ pid: 123,
377
+ output: [],
378
+ signal: null,
379
+ };
380
+ });
381
+
382
+ vi.mocked(fs.existsSync).mockReturnValue(false);
383
+
384
+ const adapter = new GitHubPagesAdapter({ repo: "user/my-site" });
385
+ const context = createContext();
386
+
387
+ const result = await adapter.deploy(context);
388
+
389
+ expect(result.success).toBe(true);
390
+
391
+ // Verify git commands were called
392
+ expect(gitCalls).toContainEqual(["init"]);
393
+ expect(gitCalls).toContainEqual(["add", "-A"]);
394
+ expect(gitCalls).toContainEqual([
395
+ "commit",
396
+ "-m",
397
+ "Deploy to GitHub Pages",
398
+ ]);
399
+ expect(
400
+ gitCalls.some(
401
+ (call) =>
402
+ call[0] === "remote" &&
403
+ call[1] === "add" &&
404
+ call[3] === "https://github.com/user/my-site.git"
405
+ )
406
+ ).toBe(true);
407
+ expect(gitCalls).toContainEqual([
408
+ "push",
409
+ "-f",
410
+ "origin",
411
+ "HEAD:gh-pages",
412
+ ]);
413
+ });
414
+
415
+ it("should use custom branch name", async () => {
416
+ const gitCalls: string[][] = [];
417
+ vi.mocked(childProcess.spawnSync).mockImplementation((cmd, args) => {
418
+ if (cmd === "git") {
419
+ gitCalls.push(args as string[]);
420
+ }
421
+ return {
422
+ status: 0,
423
+ stdout: "",
424
+ stderr: "",
425
+ pid: 123,
426
+ output: [],
427
+ signal: null,
428
+ };
429
+ });
430
+
431
+ vi.mocked(fs.existsSync).mockReturnValue(false);
432
+
433
+ const adapter = new GitHubPagesAdapter({
434
+ repo: "user/my-site",
435
+ branch: "docs",
436
+ });
437
+ const context = createContext();
438
+
439
+ await adapter.deploy(context);
440
+
441
+ expect(gitCalls).toContainEqual(["push", "-f", "origin", "HEAD:docs"]);
442
+ });
443
+
444
+ it("should use custom commit message", async () => {
445
+ const gitCalls: string[][] = [];
446
+ vi.mocked(childProcess.spawnSync).mockImplementation((cmd, args) => {
447
+ if (cmd === "git") {
448
+ gitCalls.push(args as string[]);
449
+ }
450
+ return {
451
+ status: 0,
452
+ stdout: "",
453
+ stderr: "",
454
+ pid: 123,
455
+ output: [],
456
+ signal: null,
457
+ };
458
+ });
459
+
460
+ vi.mocked(fs.existsSync).mockReturnValue(false);
461
+
462
+ const adapter = new GitHubPagesAdapter({
463
+ repo: "user/my-site",
464
+ message: "Custom deploy",
465
+ });
466
+ const context = createContext();
467
+
468
+ await adapter.deploy(context);
469
+
470
+ expect(gitCalls).toContainEqual(["commit", "-m", "Custom deploy"]);
471
+ });
472
+
473
+ it("should use adapterConfig options over constructor config", async () => {
474
+ const gitCalls: string[][] = [];
475
+ vi.mocked(childProcess.spawnSync).mockImplementation((cmd, args) => {
476
+ if (cmd === "git") {
477
+ gitCalls.push(args as string[]);
478
+ }
479
+ return {
480
+ status: 0,
481
+ stdout: "",
482
+ stderr: "",
483
+ pid: 123,
484
+ output: [],
485
+ signal: null,
486
+ };
487
+ });
488
+
489
+ vi.mocked(fs.existsSync).mockReturnValue(false);
490
+
491
+ const adapter = new GitHubPagesAdapter({
492
+ repo: "user/default-repo",
493
+ branch: "default-branch",
494
+ message: "Default message",
495
+ });
496
+
497
+ const context = createContext({
498
+ adapterConfig: {
499
+ repo: "user/custom-repo",
500
+ branch: "custom-branch",
501
+ message: "Custom message",
502
+ },
503
+ });
504
+
505
+ const result = await adapter.deploy(context);
506
+
507
+ expect(result.success).toBe(true);
508
+ expect(gitCalls).toContainEqual(["commit", "-m", "Custom message"]);
509
+ expect(gitCalls).toContainEqual([
510
+ "push",
511
+ "-f",
512
+ "origin",
513
+ "HEAD:custom-branch",
514
+ ]);
515
+ expect(
516
+ gitCalls.some(
517
+ (call) =>
518
+ call[0] === "remote" &&
519
+ call[1] === "add" &&
520
+ call[3] === "https://github.com/user/custom-repo.git"
521
+ )
522
+ ).toBe(true);
523
+ });
524
+
525
+ it("should return failure when git init fails", async () => {
526
+ vi.mocked(childProcess.spawnSync).mockImplementation((cmd, args) => {
527
+ if (cmd === "git" && (args as string[])[0] === "init") {
528
+ return {
529
+ status: 1,
530
+ stdout: "",
531
+ stderr: "fatal: not a git repository",
532
+ pid: 123,
533
+ output: [],
534
+ signal: null,
535
+ };
536
+ }
537
+ return {
538
+ status: 0,
539
+ stdout: "",
540
+ stderr: "",
541
+ pid: 123,
542
+ output: [],
543
+ signal: null,
544
+ };
545
+ });
546
+
547
+ vi.mocked(fs.existsSync).mockReturnValue(false);
548
+
549
+ const adapter = new GitHubPagesAdapter({ repo: "user/my-site" });
550
+ const context = createContext();
551
+
552
+ const result = await adapter.deploy(context);
553
+
554
+ expect(result.success).toBe(false);
555
+ expect(result.error).toContain("Failed to initialize git repository");
556
+ });
557
+
558
+ it("should return failure when git push fails", async () => {
559
+ vi.mocked(childProcess.spawnSync).mockImplementation((cmd, args) => {
560
+ if (cmd === "git" && (args as string[])[0] === "push") {
561
+ return {
562
+ status: 1,
563
+ stdout: "",
564
+ stderr: "Permission denied",
565
+ pid: 123,
566
+ output: [],
567
+ signal: null,
568
+ };
569
+ }
570
+ return {
571
+ status: 0,
572
+ stdout: "",
573
+ stderr: "",
574
+ pid: 123,
575
+ output: [],
576
+ signal: null,
577
+ };
578
+ });
579
+
580
+ vi.mocked(fs.existsSync).mockReturnValue(false);
581
+
582
+ const adapter = new GitHubPagesAdapter({ repo: "user/my-site" });
583
+ const context = createContext();
584
+
585
+ const result = await adapter.deploy(context);
586
+
587
+ expect(result.success).toBe(false);
588
+ expect(result.error).toContain("Failed to push to GitHub");
589
+ });
590
+
591
+ it("should return failure when repo auto-detection fails", async () => {
592
+ vi.mocked(childProcess.spawnSync).mockImplementation((cmd, args) => {
593
+ if (cmd === "git" && (args as string[])[0] === "remote") {
594
+ return {
595
+ status: 1,
596
+ stdout: "",
597
+ stderr: "fatal: not a git repository",
598
+ pid: 123,
599
+ output: [],
600
+ signal: null,
601
+ };
602
+ }
603
+ return {
604
+ status: 0,
605
+ stdout: "",
606
+ stderr: "",
607
+ pid: 123,
608
+ output: [],
609
+ signal: null,
610
+ };
611
+ });
612
+
613
+ const adapter = new GitHubPagesAdapter(); // No repo specified
614
+ const context = createContext();
615
+
616
+ const result = await adapter.deploy(context);
617
+
618
+ expect(result.success).toBe(false);
619
+ expect(result.error).toContain("Could not auto-detect repository");
620
+ });
621
+
622
+ it("should auto-detect repo from HTTPS remote URL", async () => {
623
+ vi.mocked(childProcess.spawnSync).mockImplementation((cmd, args) => {
624
+ const argsList = args as string[];
625
+ if (
626
+ cmd === "git" &&
627
+ argsList[0] === "remote" &&
628
+ argsList[1] === "get-url"
629
+ ) {
630
+ return {
631
+ status: 0,
632
+ stdout: "https://github.com/user/my-repo.git\n",
633
+ stderr: "",
634
+ pid: 123,
635
+ output: [],
636
+ signal: null,
637
+ };
638
+ }
639
+ return {
640
+ status: 0,
641
+ stdout: "",
642
+ stderr: "",
643
+ pid: 123,
644
+ output: [],
645
+ signal: null,
646
+ };
647
+ });
648
+
649
+ vi.mocked(fs.existsSync).mockReturnValue(false);
650
+
651
+ const adapter = new GitHubPagesAdapter();
652
+ const logger = createLogger();
653
+ const context = createContext({ logger });
654
+
655
+ const result = await adapter.deploy(context);
656
+
657
+ expect(result.success).toBe(true);
658
+ expect(logger.logs.some((l) => l.includes("Auto-detected"))).toBe(true);
659
+ expect(logger.logs.some((l) => l.includes("user/my-repo"))).toBe(true);
660
+ });
661
+
662
+ it("should auto-detect repo from SSH remote URL", async () => {
663
+ vi.mocked(childProcess.spawnSync).mockImplementation((cmd, args) => {
664
+ const argsList = args as string[];
665
+ if (
666
+ cmd === "git" &&
667
+ argsList[0] === "remote" &&
668
+ argsList[1] === "get-url"
669
+ ) {
670
+ return {
671
+ status: 0,
672
+ stdout: "git@github.com:user/my-repo.git\n",
673
+ stderr: "",
674
+ pid: 123,
675
+ output: [],
676
+ signal: null,
677
+ };
678
+ }
679
+ return {
680
+ status: 0,
681
+ stdout: "",
682
+ stderr: "",
683
+ pid: 123,
684
+ output: [],
685
+ signal: null,
686
+ };
687
+ });
688
+
689
+ vi.mocked(fs.existsSync).mockReturnValue(false);
690
+
691
+ const adapter = new GitHubPagesAdapter();
692
+ const logger = createLogger();
693
+ const context = createContext({ logger });
694
+
695
+ const result = await adapter.deploy(context);
696
+
697
+ expect(result.success).toBe(true);
698
+ expect(logger.logs.some((l) => l.includes("user/my-repo"))).toBe(true);
699
+ });
700
+
701
+ it("should return correct URL for user.github.io repos", async () => {
702
+ vi.mocked(childProcess.spawnSync).mockReturnValue({
703
+ status: 0,
704
+ stdout: "",
705
+ stderr: "",
706
+ pid: 123,
707
+ output: [],
708
+ signal: null,
709
+ });
710
+
711
+ vi.mocked(fs.existsSync).mockReturnValue(false);
712
+
713
+ const adapter = new GitHubPagesAdapter({
714
+ repo: "username/username.github.io",
715
+ });
716
+ const context = createContext();
717
+
718
+ const result = await adapter.deploy(context);
719
+
720
+ expect(result.success).toBe(true);
721
+ expect(result.url).toBe("https://username.github.io");
722
+ });
723
+
724
+ it("should return correct URL for project repos", async () => {
725
+ vi.mocked(childProcess.spawnSync).mockReturnValue({
726
+ status: 0,
727
+ stdout: "",
728
+ stderr: "",
729
+ pid: 123,
730
+ output: [],
731
+ signal: null,
732
+ });
733
+
734
+ vi.mocked(fs.existsSync).mockReturnValue(false);
735
+
736
+ const adapter = new GitHubPagesAdapter({ repo: "org/my-project" });
737
+ const context = createContext();
738
+
739
+ const result = await adapter.deploy(context);
740
+
741
+ expect(result.success).toBe(true);
742
+ expect(result.url).toBe("https://org.github.io/my-project");
743
+ });
744
+ });
745
+ });
746
+
747
+ describe("githubPagesAdapter factory", () => {
748
+ it("should create GitHubPagesAdapter instance", () => {
749
+ const adapter = githubPagesAdapter({ repo: "user/repo" });
750
+ expect(adapter).toBeInstanceOf(GitHubPagesAdapter);
751
+ expect(adapter.name).toBe("github-pages");
752
+ });
753
+
754
+ it("should create adapter with default config when no options provided", () => {
755
+ const adapter = githubPagesAdapter();
756
+ expect(adapter).toBeInstanceOf(GitHubPagesAdapter);
757
+ expect(adapter.name).toBe("github-pages");
758
+ });
759
+ });