@salesforcedevs/sfdocs-e2e 1.0.11 → 1.0.12-e2e-topic-version-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.
@@ -85,7 +85,7 @@ describe('Docs content type', () => {
85
85
  await parentTile.click();
86
86
  await page.waitPageLoad();
87
87
 
88
- expect(await browser.getUrl()).toContain('parent-with-refs.html');
88
+ expect(await browser.getUrl()).toContain('errors-and-rate-limits.html');
89
89
  expect(await (await page.getContentHeading()).getText()).toContain(
90
90
  'Errors and Rate Limits',
91
91
  );
@@ -197,7 +197,7 @@ describe('Docs content type > internal links', () => {
197
197
 
198
198
  describe('Docs content type > spec (Redoc) topic', () => {
199
199
  beforeEach(async () => {
200
- page = new DocsPage('/docs/docs-content-type-example/sample-api');
200
+ page = new DocsPage('/docs/docs-content-type-example/widgets-api-reference');
201
201
  page.open();
202
202
  await page.waitForRedocLoad();
203
203
  });
@@ -218,7 +218,7 @@ describe('Docs content type > spec (Redoc) topic', () => {
218
218
 
219
219
  it('falls back to the landing topic when the back link is clicked on a directly opened spec', async () => {
220
220
  await browser.reloadSession();
221
- page = new DocsPage('/docs/docs-content-type-example/sample-api');
221
+ page = new DocsPage('/docs/docs-content-type-example/widgets-api-reference');
222
222
  page.open();
223
223
  await page.waitForRedocLoad();
224
224
 
@@ -245,7 +245,7 @@ describe('Docs content type > locale picker', () => {
245
245
  });
246
246
 
247
247
  it('shows the language picker on a spec topic of a localized project', async () => {
248
- page = new DocsPage('/docs/docs-content-type-example/sample-api');
248
+ page = new DocsPage('/docs/docs-content-type-example/widgets-api-reference');
249
249
  page.open();
250
250
  await page.waitForRedocLoad();
251
251
 
@@ -256,7 +256,7 @@ describe('Docs content type > locale picker', () => {
256
256
  });
257
257
 
258
258
  it('re-renders the spec in the selected locale when switching language on a spec page', async () => {
259
- page = new DocsPage('/docs/docs-content-type-example/sample-api');
259
+ page = new DocsPage('/docs/docs-content-type-example/widgets-api-reference');
260
260
  page.open();
261
261
  await page.waitForRedocLoad();
262
262
 
@@ -290,6 +290,292 @@ describe('Docs content type > locale picker', () => {
290
290
  });
291
291
  });
292
292
 
293
+ describe('Docs content type > localized (ja-jp) rendering', () => {
294
+ it('renders the Japanese body and sidebar on a ja-jp markdown topic', async () => {
295
+ page = new DocsPage('/docs/ja-jp/docs-content-type-example/get-started.html');
296
+ page.open();
297
+ await page.waitPageLoad();
298
+ await page.waitForSidebar();
299
+
300
+ expect(await (await page.getContentHeading()).getText()).toContain(
301
+ 'ウィジェット サービスを始める',
302
+ );
303
+ // Sidebar tiles are localized — the Japanese "Widget Concepts" label resolves.
304
+ const tile = await page.getSidebarTile('ウィジェットの概念');
305
+ expect(await tile.isExisting()).toBe(true);
306
+ });
307
+
308
+ it('renders the Redoc view from a ja-jp spec URL', async () => {
309
+ page = new DocsPage('/docs/ja-jp/docs-content-type-example/widgets-api-reference');
310
+ page.open();
311
+ await page.waitForRedocLoad();
312
+
313
+ expect(await browser.getUrl()).toContain('/ja-jp/');
314
+ expect(await (await page.getRedocApiTitle()).getText()).not.toBe('');
315
+ });
316
+ });
317
+
318
+ describe('Docs content type > englishonly filter', () => {
319
+ it('serves the englishonly topic in English', async () => {
320
+ page = new DocsPage('/docs/docs-content-type-example/us-compliance-notes.html');
321
+ page.open();
322
+ await page.waitPageLoad();
323
+
324
+ expect(await (await page.getContentHeading()).getText()).toContain('US Compliance Notes');
325
+ });
326
+ });
327
+
328
+ describe('Docs content type > language picker round-trip', () => {
329
+ it('switches a markdown topic between English and Japanese and back', async () => {
330
+ page = new DocsPage('/docs/docs-content-type-example/get-started.html');
331
+ page.open();
332
+ await page.waitPageLoad();
333
+ await page.waitForSidebar();
334
+
335
+ await page.selectLanguage('日本語');
336
+ await page.waitPageLoad();
337
+ expect(await browser.getUrl()).toContain('/ja-jp/');
338
+ expect(await browser.getUrl()).toContain('get-started.html');
339
+ expect(await (await page.getContentHeading()).getText()).toContain(
340
+ 'ウィジェット サービスを始める',
341
+ );
342
+
343
+ await page.selectLanguage('English');
344
+ await page.waitPageLoad();
345
+ expect(await browser.getUrl()).not.toContain('/ja-jp/');
346
+ expect(await browser.getUrl()).toContain('get-started.html');
347
+ expect(await (await page.getContentHeading()).getText()).toContain('Get Started');
348
+ });
349
+ });
350
+
351
+ describe('Docs content type > external link', () => {
352
+ it('exposes the real href and opens the external link in a new tab', async () => {
353
+ page = new DocsPage('/docs/docs-content-type-example/get-started.html');
354
+ page.open();
355
+ await page.waitPageLoad();
356
+ await page.waitForSidebar();
357
+
358
+ const anchor = await page.getTileAnchor('Salesforce Developers');
359
+ expect(await anchor.getAttribute('href')).toContain('https://developer.salesforce.com');
360
+ expect(await anchor.getAttribute('target')).toBe('_blank');
361
+ });
362
+ });
363
+
364
+ describe('Docs content type > Liquid templating', () => {
365
+ beforeEach(async () => {
366
+ page = new DocsPage('/docs/docs-content-type-example/liquid-widgets.html');
367
+ page.open();
368
+ await page.waitPageLoad();
369
+ });
370
+
371
+ it('resolves frontmatter assigns and liquid.data values in the body', async () => {
372
+ const content = await $('>>>doc-content-layout');
373
+ const text = await content.getText();
374
+ const html = await content.getHTML();
375
+
376
+ expect(text).toContain('Widget Automation');
377
+ expect(text).toContain('Hello from the docs liquid data file');
378
+ expect(html).not.toContain('{% assign');
379
+ expect(html).not.toContain('{{ feature }}');
380
+ expect(html).not.toContain('{{ data.tagline }}');
381
+ });
382
+
383
+ it('resolves repository-level variables from content-config.yml', async () => {
384
+ const content = await $('>>>doc-content-layout');
385
+ const text = await content.getText();
386
+ const html = await content.getHTML();
387
+
388
+ expect(text).toContain('Salesforce Platform');
389
+ expect(text).toContain('62.0');
390
+ expect(html).not.toContain('{{ variables.platform');
391
+ });
392
+
393
+ it('renders a loop over a liquid.data array', async () => {
394
+ const content = await $('>>>doc-content-layout');
395
+ const text = await content.getText();
396
+ const html = await content.getHTML();
397
+
398
+ expect(text).toContain('createWidget()');
399
+ expect(text).toContain('updateWidget()');
400
+ expect(text).toContain('deleteWidget()');
401
+ expect(html).not.toContain('for operation in data.operations');
402
+ });
403
+
404
+ it('resolves output expressions inside code blocks but keeps tags literal', async () => {
405
+ const codeBlockElement = await $('>>>.code-block-content');
406
+ const codeBlock = await codeBlockElement.shadow$('code');
407
+
408
+ expect(await codeBlock.isExisting()).toBeTruthy();
409
+
410
+ const codeText = await codeBlock.getText();
411
+ // {{ }} outputs resolve even inside code blocks.
412
+ expect(codeText).not.toContain('{{ data.tagline }}');
413
+ expect(codeText).toContain('Hello from the docs liquid data file');
414
+ expect(codeText).toContain('Widget Automation');
415
+ // {% %} tags stay literal inside code blocks.
416
+ expect(codeText).toContain('for op in ops');
417
+ });
418
+
419
+ it('renders a shared partial pulled in via include and its capture blocks', async () => {
420
+ const content = await $('>>>doc-content-layout');
421
+ const text = await content.getText();
422
+ const html = await content.getHTML();
423
+
424
+ expect(text).toContain('Reusable Tip');
425
+ expect(text).toContain('Widgets are created and managed through the Widgets API');
426
+ expect(text).toContain('Reusable Note');
427
+ expect(text).toContain('Every widget has a unique identifier');
428
+ // Dash-form tags are the fixture's real (resolved) tags; the bare "{% include %}"
429
+ // in the prose renders as literal inline code, so assert on the dash form only.
430
+ expect(html).not.toContain('{%- include');
431
+ expect(html).not.toContain('{%- capture');
432
+ expect(html).not.toContain('{{ liquid-widgets-reuse-tip }}');
433
+ });
434
+ });
435
+
436
+ describe('Docs content type > Liquid data object format', () => {
437
+ it('loads multiple data files each under a named key', async () => {
438
+ page = new DocsPage('/docs/docs-content-type-example/liquid-multi-data.html');
439
+ page.open();
440
+ await page.waitPageLoad();
441
+
442
+ const content = await $('>>>doc-content-layout');
443
+ const text = await content.getText();
444
+ const html = await content.getHTML();
445
+
446
+ expect(text).toContain('Hello from the docs liquid data file');
447
+ expect(text).toContain('Second data file loaded under a named key');
448
+ expect(html).not.toContain('{{ data.one.tagline }}');
449
+ expect(html).not.toContain('{{ two.summary }}');
450
+ });
451
+ });
452
+
453
+ describe('Docs content type > Liquid templating (ja-jp)', () => {
454
+ let jaLiquidEnabled = false;
455
+ const widgetsPath = '/docs/ja-jp/docs-content-type-example/liquid-widgets.html';
456
+
457
+ before(async () => {
458
+ try {
459
+ page = new DocsPage(widgetsPath);
460
+ page.open();
461
+ await page.waitPageLoad();
462
+
463
+ const content = await $('>>>doc-content-layout');
464
+ const text = await content.getText();
465
+ const html = await content.getHTML();
466
+
467
+ const hasLiquidOutput = text.includes(
468
+ 'ドキュメント Liquid データ ファイルからこんにちは',
469
+ );
470
+ const hasRawSyntax = html.includes('{% assign') || html.includes('{{ data.tagline }}');
471
+
472
+ jaLiquidEnabled = hasLiquidOutput && !hasRawSyntax;
473
+ } catch (e) {
474
+ jaLiquidEnabled = false;
475
+ }
476
+ });
477
+
478
+ beforeEach(async () => {
479
+ if (jaLiquidEnabled) {
480
+ page = new DocsPage(widgetsPath);
481
+ page.open();
482
+ await page.waitPageLoad();
483
+ }
484
+ });
485
+
486
+ it('resolves frontmatter assigns and liquid.data values in a localized topic', async function () {
487
+ if (!jaLiquidEnabled) {
488
+ this.skip();
489
+ }
490
+
491
+ const content = await $('>>>doc-content-layout');
492
+ const text = await content.getText();
493
+ const html = await content.getHTML();
494
+
495
+ expect(text).toContain('ウィジェット オートメーション');
496
+ expect(text).toContain('ドキュメント Liquid データ ファイルからこんにちは');
497
+ expect(html).not.toContain('{% assign');
498
+ expect(html).not.toContain('{{ data.tagline }}');
499
+ });
500
+
501
+ it('resolves repository-level variables in a localized topic', async function () {
502
+ if (!jaLiquidEnabled) {
503
+ this.skip();
504
+ }
505
+
506
+ const content = await $('>>>doc-content-layout');
507
+ const text = await content.getText();
508
+ const html = await content.getHTML();
509
+
510
+ expect(text).toContain('Salesforce Platform');
511
+ expect(text).toContain('62.0');
512
+ expect(html).not.toContain('{{ variables.platform');
513
+ });
514
+
515
+ it('renders a loop and an included partial capture block in a localized topic', async function () {
516
+ if (!jaLiquidEnabled) {
517
+ this.skip();
518
+ }
519
+
520
+ const content = await $('>>>doc-content-layout');
521
+ const text = await content.getText();
522
+ const html = await content.getHTML();
523
+
524
+ expect(text).toContain('createWidget()');
525
+ expect(text).toContain('再利用可能なヒント');
526
+ expect(text).toContain('ウィジェットは Widgets API を通じて作成および管理されます');
527
+ expect(html).not.toContain('for operation in data.operations');
528
+ expect(html).not.toContain('{%- include');
529
+ expect(html).not.toContain('{%- capture');
530
+ });
531
+ });
532
+
533
+ describe('Docs content type > Liquid data object format (ja-jp)', () => {
534
+ let jaLiquidEnabled = false;
535
+ const multiDataPath = '/docs/ja-jp/docs-content-type-example/liquid-multi-data.html';
536
+
537
+ before(async () => {
538
+ try {
539
+ page = new DocsPage(multiDataPath);
540
+ page.open();
541
+ await page.waitPageLoad();
542
+
543
+ const content = await $('>>>doc-content-layout');
544
+ const text = await content.getText();
545
+ const html = await content.getHTML();
546
+
547
+ const hasLiquidOutput = text.includes(
548
+ 'ドキュメント Liquid データ ファイルからこんにちは',
549
+ );
550
+ const hasRawSyntax =
551
+ html.includes('{{ data.one.tagline }}') || html.includes('{{ two.summary }}');
552
+
553
+ jaLiquidEnabled = hasLiquidOutput && !hasRawSyntax;
554
+ } catch (e) {
555
+ jaLiquidEnabled = false;
556
+ }
557
+ });
558
+
559
+ it('loads multiple data files each under a named key in a localized topic', async function () {
560
+ if (!jaLiquidEnabled) {
561
+ this.skip();
562
+ }
563
+
564
+ page = new DocsPage(multiDataPath);
565
+ page.open();
566
+ await page.waitPageLoad();
567
+
568
+ const content = await $('>>>doc-content-layout');
569
+ const text = await content.getText();
570
+ const html = await content.getHTML();
571
+
572
+ expect(text).toContain('ドキュメント Liquid データ ファイルからこんにちは');
573
+ expect(text).toContain('名前付きキーの下に読み込まれる 2 番目のデータ ファイル');
574
+ expect(html).not.toContain('{{ data.one.tagline }}');
575
+ expect(html).not.toContain('{{ two.summary }}');
576
+ });
577
+ });
578
+
293
579
  describe('Docs content type > error routes', () => {
294
580
  const expectNotFoundPage = async (): Promise<void> => {
295
581
  const errorComponent = await $('dx-error');
@@ -1,3 +1,4 @@
1
+ import DocsPage from '../pageobjects/docs.page';
1
2
  import GuidePage from '../pageobjects/guide.page';
2
3
 
3
4
  let page: GuidePage;
@@ -54,3 +55,56 @@ describe('Liquid Template Rendering — Advanced', () => {
54
55
  expect(text.includes('previewFuture')).toBeTruthy();
55
56
  });
56
57
  });
58
+
59
+ describe('Docs content type > future filter', () => {
60
+ let docsFutureEnabled = false;
61
+ const overviewPath = '/docs/docs-content-type-example/get-started.html';
62
+
63
+ before(async () => {
64
+ try {
65
+ const docsPage = new DocsPage(overviewPath);
66
+ docsPage.open();
67
+ await docsPage.waitPageLoad();
68
+
69
+ const content = await $('>>>doc-content-layout');
70
+ const text = await content.getText();
71
+
72
+ docsFutureEnabled = text.includes(
73
+ 'hidden in production and excluded from localization unless',
74
+ );
75
+ } catch (e) {
76
+ docsFutureEnabled = false;
77
+ }
78
+ });
79
+
80
+ it('renders an inline future block when previewFuture is enabled', async function () {
81
+ if (!docsFutureEnabled) {
82
+ this.skip();
83
+ }
84
+
85
+ const docsPage = new DocsPage(overviewPath);
86
+ docsPage.open();
87
+ await docsPage.waitPageLoad();
88
+
89
+ const content = await $('>>>doc-content-layout');
90
+ const text = await content.getText();
91
+ const html = await content.getHTML();
92
+
93
+ expect(text).toContain('hidden in production and excluded from localization unless');
94
+ expect(html).not.toContain('{% future');
95
+ });
96
+
97
+ it('renders the future topic page when previewFuture is enabled', async function () {
98
+ if (!docsFutureEnabled) {
99
+ this.skip();
100
+ }
101
+
102
+ const docsPage = new DocsPage('/docs/docs-content-type-example/upcoming-graphql.html');
103
+ docsPage.open();
104
+ await docsPage.waitPageLoad();
105
+
106
+ expect(await (await docsPage.getContentHeading()).getText()).toContain(
107
+ 'Upcoming: GraphQL API',
108
+ );
109
+ });
110
+ });
@@ -222,3 +222,100 @@ describe('Liquid Template Rendering', () => {
222
222
  expect(text.includes('Liquid is a templating language supported in SFDocs')).toBeTruthy();
223
223
  });
224
224
  });
225
+
226
+ describe('Liquid Template Rendering — Localized (ja-jp)', () => {
227
+ let jaLiquidEnabled = false;
228
+ const quickstartPath = '/docs/ja-jp/liquid-project/guide/liquid-quickstart.html';
229
+
230
+ before(async () => {
231
+ try {
232
+ page = new GuidePage(quickstartPath);
233
+ await browser.url(page.path);
234
+ await page.waitPageLoad();
235
+
236
+ const content = await $('>>>doc-content-layout');
237
+ const text = await content.getText();
238
+ const html = await content.getHTML();
239
+
240
+ const hasLiquidOutput = text.includes('data.yaml からこんにちは');
241
+ const hasRawSyntax =
242
+ html.includes('{% assign topic') || html.includes('{{ data.greeting }}');
243
+
244
+ jaLiquidEnabled = hasLiquidOutput && !hasRawSyntax;
245
+ } catch (e) {
246
+ jaLiquidEnabled = false;
247
+ }
248
+ });
249
+
250
+ beforeEach(async () => {
251
+ if (jaLiquidEnabled) {
252
+ page = new GuidePage(quickstartPath);
253
+ await browser.url(page.path);
254
+ await page.waitPageLoad();
255
+ }
256
+ });
257
+
258
+ it('Should render frontmatter assigns and data.yaml values in Japanese', async function () {
259
+ if (!jaLiquidEnabled) {
260
+ this.skip();
261
+ }
262
+
263
+ const content = await $('>>>doc-content-layout');
264
+ const text = await content.getText();
265
+
266
+ expect(text.includes('ライターのための GitHub')).toBeTruthy();
267
+ expect(text.includes('data.yaml からこんにちは')).toBeTruthy();
268
+ });
269
+
270
+ it('Should render repository-level variables in a localized topic', async function () {
271
+ if (!jaLiquidEnabled) {
272
+ this.skip();
273
+ }
274
+
275
+ const content = await $('>>>doc-content-layout');
276
+ const text = await content.getText();
277
+ const html = await content.getHTML();
278
+
279
+ expect(text.includes('Salesforce Platform')).toBeTruthy();
280
+ expect(text.includes('62.0')).toBeTruthy();
281
+ expect(html.includes('{{ variables.platform')).toBeFalsy();
282
+ });
283
+
284
+ it('Should render a loop and an included partial capture block in Japanese', async function () {
285
+ if (!jaLiquidEnabled) {
286
+ this.skip();
287
+ }
288
+
289
+ const content = await $('>>>doc-content-layout');
290
+ const text = await content.getText();
291
+ const html = await content.getHTML();
292
+
293
+ expect(text.includes('create()')).toBeTruthy();
294
+ expect(text.includes('再利用可能なヒント')).toBeTruthy();
295
+ expect(
296
+ text.includes('ウィジェットは Widgets API を通じて作成および管理されます'),
297
+ ).toBeTruthy();
298
+ // Dash-form tags are the fixture's real (resolved) tags; the bare "{% include %}"
299
+ // in the prose renders as literal inline code, so assert on the dash form only.
300
+ expect(html.includes('{%- include')).toBeFalsy();
301
+ expect(html.includes('{%- capture')).toBeFalsy();
302
+ });
303
+
304
+ it('Should render liquid.data object format in a localized topic', async function () {
305
+ if (!jaLiquidEnabled) {
306
+ this.skip();
307
+ }
308
+
309
+ const multiDataPage = new GuidePage('/docs/ja-jp/liquid-project/guide/multi-data.html');
310
+ await browser.url(multiDataPage.path);
311
+ await multiDataPage.waitPageLoad();
312
+
313
+ const content = await $('>>>doc-content-layout');
314
+ const text = await content.getText();
315
+ const html = await content.getHTML();
316
+
317
+ expect(text.includes('小売店舗や顧客サイト')).toBeTruthy();
318
+ expect(html.includes('{{ data.one.summary }}')).toBeFalsy();
319
+ expect(html.includes('{{ two.summary }}')).toBeFalsy();
320
+ });
321
+ });
@@ -187,11 +187,9 @@ describe('Redoc API Reference page', () => {
187
187
 
188
188
  it('should show arrow button after OAS reference titles', async () => {
189
189
  const sideBarContent = await refPage.getSidebarItems();
190
-
191
- const secondItem = sideBarContent[1];
192
- const treeItem = await secondItem.shadow$('dx-tree-item');
193
- const treeTile = await treeItem.shadow$('a > dx-tree-tile');
194
- const arrowIcon = await treeTile.shadow$(
190
+ const treeItem = await sideBarContent[1].shadow$('dx-tree-item');
191
+ const tile = await refPage.getTreeItemTile(treeItem);
192
+ const arrowIcon = await tile.shadow$(
195
193
  'a > div[role="heading"] > div.tile-forward-arrow',
196
194
  );
197
195
 
@@ -106,7 +106,7 @@ describe('Reference Versioning', () => {
106
106
  const versionBtn = await $('>>>.version-picker-button');
107
107
  await versionBtn.waitForDisplayed();
108
108
  await versionBtn.click();
109
- const versionOptions = await $$('>>>doc-version-picker dx-dropdown-option');
109
+ const versionOptions = await referencePage.getVersionOptions();
110
110
 
111
111
  expect(versionOptions.length).toEqual(2);
112
112
  expect(await (await versionOptions[0].shadow$('div>div')).getText()).toEqual('0.1.3');
@@ -131,7 +131,7 @@ describe('Reference Versioning', () => {
131
131
  await versionBtn.waitForDisplayed();
132
132
  await versionBtn.click();
133
133
 
134
- const versionOptions = await $$('>>>doc-version-picker dx-dropdown-option');
134
+ const versionOptions = await referencePage.getVersionOptions();
135
135
 
136
136
  await versionOptions[1].waitForClickable();
137
137
  await versionOptions[1].click();
@@ -150,7 +150,7 @@ describe('Reference Versioning', () => {
150
150
  await versionPicker.waitForDisplayed();
151
151
  await versionPicker.click();
152
152
 
153
- const versionOptions = await $$('>>>doc-version-picker dx-dropdown-option');
153
+ const versionOptions = await referencePage.getVersionOptions();
154
154
  const selectedVersionText = await (await versionOptions[1].shadow$('div>div')).getText();
155
155
 
156
156
  await versionOptions[1].click();