@salesforcedevs/sfdocs-e2e 1.0.12-e2e-topic-version → 1.0.12-e2e-tests-1

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@salesforcedevs/sfdocs-e2e",
3
- "version": "1.0.12-e2e-topic-version",
3
+ "version": "1.0.12-e2e-tests-1",
4
4
  "description": "E2E test suite for SFDocs static portal pages (SSG)",
5
5
  "license": "ISC",
6
6
  "bin": {
@@ -15,10 +15,6 @@ class DocsPage extends Page {
15
15
  });
16
16
  }
17
17
 
18
- async getContentHeading(): Promise<WebdriverIO.Element> {
19
- return (await $('doc-unified-content-layout')).$('div.markdown-content h1');
20
- }
21
-
22
18
  async getSidebarTile(label: string): Promise<WebdriverIO.Element> {
23
19
  return this.getSidebarTreeItemByLabel(label);
24
20
  }
@@ -58,6 +58,10 @@ export default class Page {
58
58
  ).waitForDisplayed({ timeout: this.REFERENCE_LOAD_WAIT_TIME });
59
59
  }
60
60
 
61
+ async getContentHeading(): Promise<WebdriverIO.Element> {
62
+ return (await $('doc-unified-content-layout')).$('div.markdown-content h1');
63
+ }
64
+
61
65
  async waitForGuidePageLoad(): Promise<void> {
62
66
  await $('doc-content-layout').waitForDisplayed({ timeout: 5000 });
63
67
  }
@@ -1,5 +1,8 @@
1
1
  import Page from './page';
2
2
 
3
+ /** Must match the sessionStorage key the doc-version-picker component writes to. */
4
+ const TOPIC_VERSION_SELECTIONS_SESSION_KEY = 'sfdocs-topic-version-selections';
5
+
3
6
  /**
4
7
  * Page object for topic-level (per-topic) version picker interactions.
5
8
  *
@@ -138,11 +141,30 @@ export default class TopicVersionPage extends Page {
138
141
  throw new Error(`No version option found with label "${label}"`);
139
142
  }
140
143
 
144
+ private async waitForUrlCondition(
145
+ description: string,
146
+ predicate: (url: string) => boolean,
147
+ ): Promise<void> {
148
+ await browser.waitUntil(async () => predicate(await browser.getUrl()), {
149
+ timeout: 15000,
150
+ timeoutMsg: `expected URL to ${description}`,
151
+ });
152
+ }
153
+
154
+ async waitForUrlToContain(path: string): Promise<void> {
155
+ await this.waitForUrlCondition(`contain ${path}`, (url) => url.includes(path));
156
+ }
157
+
158
+ async waitForUrlToEndWith(path: string): Promise<void> {
159
+ await this.waitForUrlCondition(`end with ${path}`, (url) => url.endsWith(path));
160
+ }
161
+
141
162
  async readSessionVersionSelections(): Promise<Record<string, string> | null> {
142
163
  // The tsconfig's lib list omits "DOM", so sessionStorage isn't a known global here even
143
164
  // though this callback runs in the browser — route through globalThis to sidestep that.
144
- const raw = await browser.execute(() =>
145
- (globalThis as any).sessionStorage.getItem('sfdocs-topic-version-selections'),
165
+ const raw = await browser.execute(
166
+ (key) => (globalThis as any).sessionStorage.getItem(key),
167
+ TOPIC_VERSION_SELECTIONS_SESSION_KEY,
146
168
  );
147
169
  return raw ? JSON.parse(raw) : null;
148
170
  }
@@ -3,13 +3,23 @@ import TopicVersionPage from '../pageobjects/topic-version.page';
3
3
 
4
4
  // Fixtures live in the `docs-content-type-example` project, kept in sync between this monorepo's
5
5
  // local `packages/example-repository` and the remote `salesforcedocs/example-repository`'s
6
- // `nd/e2e-topic-version` branch (pinned in example-portal/docsportal.config.js).
6
+ // `mh/topic-level-version` branch (pinned in example-portal/docsportal.config.js).
7
7
  const BASE = '/docs/docs-content-type-example';
8
8
 
9
+ // Version labels for each fixture's picker, named so a future relabel only needs updating here.
10
+ const OAUTH_V1_LABEL = "SU'26";
11
+ const OAUTH_V2_LABEL = "Winter '26 (API version 65.0) and Spring '26 (API version 66.0)";
12
+ const ERRORS_V2_LABEL = "Summer '26 (API version 67.0)";
13
+ const ERRORS_V1_LABEL = "Spring '26 (API version 66.0)";
14
+ const CLIENT_SDKS_V2_LABEL = "WI'26";
15
+ const CLIENT_SDKS_V1_LABEL = "SU'26";
16
+ const WIDGETS_API_REFERENCE_V2_LABEL = "SU'26";
17
+ const WIDGETS_API_REFERENCE_V1_LABEL = "SP'26";
18
+
9
19
  let page: TopicVersionPage;
10
20
 
11
21
  describe('Topic-level versioning > versioned markdown topic', () => {
12
- // fixture: OAuth — latest v2 'WI'26' / older v1 'SU'26'.
22
+ // fixture: OAuth — latest is v2 (OAUTH_V2_LABEL), older is v1 (OAUTH_V1_LABEL).
13
23
  beforeEach(async () => {
14
24
  page = new TopicVersionPage(`${BASE}/oauth.html`);
15
25
  page.open();
@@ -19,7 +29,7 @@ describe('Topic-level versioning > versioned markdown topic', () => {
19
29
  it('should render the picker and default to the latest version', async () => {
20
30
  const picker = await page.getSidebarPicker('OAuth');
21
31
  expect(picker).not.toBeNull();
22
- expect(await page.getSelectedVersionLabel(picker!)).toEqual("WI'26");
32
+ expect(await page.getSelectedVersionLabel(picker!)).toEqual(OAUTH_V2_LABEL);
23
33
  expect(await page.isLatestDotShown(picker!)).toBeTruthy();
24
34
  });
25
35
 
@@ -29,20 +39,17 @@ describe('Topic-level versioning > versioned markdown topic', () => {
29
39
 
30
40
  const options = await page.getVersionOptions();
31
41
  expect(options.length).toEqual(2);
32
- expect(await page.getOptionLabel(options[0])).toEqual("WI'26");
33
- expect(await page.getOptionLabel(options[1])).toEqual("SU'26");
42
+ expect(await page.getOptionLabel(options[0])).toEqual(OAUTH_V2_LABEL);
43
+ expect(await page.getOptionLabel(options[1])).toEqual(OAUTH_V1_LABEL);
34
44
  });
35
45
 
36
46
  it('should switch the page content and URL when a non-latest version is selected', async () => {
37
47
  const picker = await page.getSidebarPicker('OAuth');
38
- await page.selectVersionByLabel(picker!, "SU'26");
48
+ await page.selectVersionByLabel(picker!, OAUTH_V1_LABEL);
39
49
  await page.waitForMarkdownTopicLoad();
40
50
 
41
- expect(await (await $('>>>h1')).getText()).toEqual('OAuth 1.0');
42
- await browser.waitUntil(
43
- async () => (await browser.getUrl()).includes(`${BASE}/v1/oauth.html`),
44
- { timeout: 15000, timeoutMsg: 'expected URL to contain /v1/oauth.html' },
45
- );
51
+ expect(await (await page.getContentHeading()).getText()).toEqual('OAuth 1.0');
52
+ await page.waitForUrlToContain(`${BASE}/v1/oauth.html`);
46
53
  });
47
54
 
48
55
  it('should return to the canonical URL when the latest version is reselected', async () => {
@@ -51,17 +58,14 @@ describe('Topic-level versioning > versioned markdown topic', () => {
51
58
  await page.waitForMarkdownTopicLoad();
52
59
 
53
60
  const picker = await page.getSidebarPicker('OAuth');
54
- await page.selectVersionByLabel(picker!, "WI'26");
61
+ await page.selectVersionByLabel(picker!, OAUTH_V2_LABEL);
55
62
  await page.waitForMarkdownTopicLoad();
56
63
 
57
- await browser.waitUntil(
58
- async () => (await browser.getUrl()).endsWith(`${BASE}/oauth.html`),
59
- { timeout: 15000, timeoutMsg: 'expected URL to end with /oauth.html' },
60
- );
64
+ await page.waitForUrlToEndWith(`${BASE}/oauth.html`);
61
65
  const url = await browser.getUrl();
62
66
  expect(url.endsWith(`${BASE}/oauth.html`)).toBeTruthy();
63
67
  expect(url).not.toContain('/v2/');
64
- expect(await (await $('>>>h1')).getText()).toEqual('OAuth 2.0');
68
+ expect(await (await page.getContentHeading()).getText()).toEqual('OAuth 2.0');
65
69
  });
66
70
 
67
71
  it('should show the "Newer Version Available" banner when the version is not latest', async () => {
@@ -80,7 +84,7 @@ describe('Topic-level versioning > versioned markdown topic', () => {
80
84
  });
81
85
 
82
86
  describe('Topic-level versioning > versioned parent with versioned child subtree', () => {
83
- // fixture: Client SDKs — latest v2 'WI'26' / older v1 'SU'26'.
87
+ // fixture: Client SDKs — latest is v2 (CLIENT_SDKS_V2_LABEL), older is v1 (CLIENT_SDKS_V1_LABEL).
84
88
  beforeEach(async () => {
85
89
  page = new TopicVersionPage(`${BASE}/android.html`);
86
90
  page.open();
@@ -90,19 +94,16 @@ describe('Topic-level versioning > versioned parent with versioned child subtree
90
94
  it('should render the picker on the parent and default to the latest version', async () => {
91
95
  const picker = await page.getSidebarPicker('Client SDKs');
92
96
  expect(picker).not.toBeNull();
93
- expect(await page.getSelectedVersionLabel(picker!)).toEqual("WI'26");
97
+ expect(await page.getSelectedVersionLabel(picker!)).toEqual(CLIENT_SDKS_V2_LABEL);
94
98
  });
95
99
 
96
100
  it('should switch the whole child subtree when the parent version changes', async () => {
97
101
  const picker = await page.getSidebarPicker('Client SDKs');
98
- await page.selectVersionByLabel(picker!, "SU'26");
102
+ await page.selectVersionByLabel(picker!, CLIENT_SDKS_V1_LABEL);
99
103
  await page.waitForMarkdownTopicLoad();
100
104
 
101
- await browser.waitUntil(
102
- async () => (await browser.getUrl()).includes(`${BASE}/v1/android.html`),
103
- { timeout: 15000, timeoutMsg: 'expected URL to contain /v1/android.html' },
104
- );
105
- expect(await (await $('>>>h1')).getText()).toEqual('Android SDK v1');
105
+ await page.waitForUrlToContain(`${BASE}/v1/android.html`);
106
+ expect(await (await page.getContentHeading()).getText()).toEqual('Android SDK v1');
106
107
 
107
108
  // Sibling child (iOS SDK) should also have moved to the v1 URL, not just this one.
108
109
  const iosItem = await page.getSidebarTreeItem('iOS SDK');
@@ -124,7 +125,7 @@ describe('Topic-level versioning > versioned parent with versioned child subtree
124
125
  await page.waitForMarkdownTopicLoad();
125
126
 
126
127
  const picker = await page.getSidebarPicker('Client SDKs');
127
- expect(await page.getSelectedVersionLabel(picker!)).toEqual("WI'26");
128
+ expect(await page.getSelectedVersionLabel(picker!)).toEqual(CLIENT_SDKS_V2_LABEL);
128
129
 
129
130
  const iosItem = await page.getSidebarTreeItem('iOS SDK');
130
131
  const iosTile = await page.getTreeItemTile(iosItem);
@@ -136,7 +137,7 @@ describe('Topic-level versioning > versioned parent with versioned child subtree
136
137
  });
137
138
 
138
139
  describe('Topic-level versioning > versioned parent with own content, subtopics and a spec subtopic', () => {
139
- // fixture: Errors and Rate Limits — latest v2 'SP'26' / older v1 'WI'25'.
140
+ // fixture: Errors and Rate Limits — latest is v2 (ERRORS_V2_LABEL), older is v1 (ERRORS_V1_LABEL).
140
141
  beforeEach(async () => {
141
142
  page = new TopicVersionPage(`${BASE}/errors-and-rate-limits.html`);
142
143
  page.open();
@@ -146,54 +147,44 @@ describe('Topic-level versioning > versioned parent with own content, subtopics
146
147
  it('should render the picker and default to the latest version', async () => {
147
148
  const picker = await page.getSidebarPicker('Errors and Rate Limits');
148
149
  expect(picker).not.toBeNull();
149
- expect(await page.getSelectedVersionLabel(picker!)).toEqual("SP'26");
150
+ expect(await page.getSelectedVersionLabel(picker!)).toEqual(ERRORS_V2_LABEL);
150
151
  });
151
152
 
152
153
  it("should switch the parent's own page content when the version changes", async () => {
153
154
  const picker = await page.getSidebarPicker('Errors and Rate Limits');
154
- await page.selectVersionByLabel(picker!, "WI'25");
155
+ await page.selectVersionByLabel(picker!, ERRORS_V1_LABEL);
155
156
  await page.waitForMarkdownTopicLoad();
156
157
 
157
- expect(await (await $('>>>h1')).getText()).toEqual('Errors and Rate Limits (v1)');
158
- await browser.waitUntil(
159
- async () => (await browser.getUrl()).includes(`${BASE}/v1/errors-and-rate-limits.html`),
160
- {
161
- timeout: 15000,
162
- timeoutMsg: 'expected URL to contain /v1/errors-and-rate-limits.html',
163
- },
158
+ expect(await (await page.getContentHeading()).getText()).toEqual(
159
+ 'Errors and Rate Limits (v1)',
164
160
  );
161
+ await page.waitForUrlToContain(`${BASE}/v1/errors-and-rate-limits.html`);
165
162
  });
166
163
 
167
164
  it('should switch the markdown subtopics when the version changes', async () => {
168
165
  const picker = await page.getSidebarPicker('Errors and Rate Limits');
169
- await page.selectVersionByLabel(picker!, "WI'25");
166
+ await page.selectVersionByLabel(picker!, ERRORS_V1_LABEL);
170
167
  await page.waitForMarkdownTopicLoad();
171
168
 
172
169
  const child = await page.getSidebarTreeItem('Common Error Codes');
173
170
  await child.click();
174
171
  await page.waitForMarkdownTopicLoad();
175
172
 
176
- expect(await (await $('>>>h1')).getText()).toEqual('Common Error Codes (v1)');
177
- await browser.waitUntil(
178
- async () => (await browser.getUrl()).includes(`${BASE}/v1/extra-child-a.html`),
179
- { timeout: 15000, timeoutMsg: 'expected URL to contain /v1/extra-child-a.html' },
180
- );
173
+ expect(await (await page.getContentHeading()).getText()).toEqual('Common Error Codes (v1)');
174
+ await page.waitForUrlToContain(`${BASE}/v1/extra-child-a.html`);
181
175
  });
182
176
 
183
177
  it('should switch the spec (Redoc) subtopic to the matching version when the version changes', async () => {
184
178
  // Key cross-type cascade: parent v1 ⇒ the nested spec subtopic is v1 too.
185
179
  const picker = await page.getSidebarPicker('Errors and Rate Limits');
186
- await page.selectVersionByLabel(picker!, "WI'25");
180
+ await page.selectVersionByLabel(picker!, ERRORS_V1_LABEL);
187
181
  await page.waitForMarkdownTopicLoad();
188
182
 
189
183
  const child = await page.getSidebarTreeItem('Another Spec API');
190
184
  await child.click();
191
185
  await page.waitForRedocTopicLoad();
192
186
 
193
- await browser.waitUntil(
194
- async () => (await browser.getUrl()).includes(`${BASE}/v1/new-sample-api`),
195
- { timeout: 15000, timeoutMsg: 'expected URL to contain /v1/new-sample-api' },
196
- );
187
+ await page.waitForUrlToContain(`${BASE}/v1/new-sample-api`);
197
188
  // v1's spec lacks the `GET /errors/{code}` operation that only v2 has — its absence
198
189
  // confirms the v1 spec asset loaded, since both versions share the same spec title.
199
190
  const getErrorCodeOperation = await $('a[href*="operation/getErrorCode"]');
@@ -208,7 +199,7 @@ describe('Topic-level versioning > versioned parent with own content, subtopics
208
199
  await page.waitForRedocTopicLoad();
209
200
 
210
201
  const redocPicker = await page.getRedocPicker();
211
- await page.selectVersionByLabel(redocPicker!, "WI'25");
202
+ await page.selectVersionByLabel(redocPicker!, ERRORS_V1_LABEL);
212
203
  await page.waitForRedocTopicLoad();
213
204
 
214
205
  page = new TopicVersionPage(`${BASE}/errors-and-rate-limits.html`);
@@ -216,7 +207,7 @@ describe('Topic-level versioning > versioned parent with own content, subtopics
216
207
  await page.waitForMarkdownTopicLoad();
217
208
 
218
209
  const parentPicker = await page.getSidebarPicker('Errors and Rate Limits');
219
- expect(await page.getSelectedVersionLabel(parentPicker!)).toEqual("WI'25");
210
+ expect(await page.getSelectedVersionLabel(parentPicker!)).toEqual(ERRORS_V1_LABEL);
220
211
  });
221
212
  });
222
213
 
@@ -232,18 +223,15 @@ describe('Topic-level versioning > standalone Redoc reference', () => {
232
223
  it('should render the Redoc version picker and default to the latest version', async () => {
233
224
  const picker = await page.getRedocPicker();
234
225
  expect(picker).not.toBeNull();
235
- expect(await page.getSelectedVersionLabel(picker!)).toEqual("SU'26");
226
+ expect(await page.getSelectedVersionLabel(picker!)).toEqual(WIDGETS_API_REFERENCE_V2_LABEL);
236
227
  });
237
228
 
238
229
  it('should switch the rendered spec when a different version is selected', async () => {
239
230
  const picker = await page.getRedocPicker();
240
- await page.selectVersionByLabel(picker!, "SP'26");
231
+ await page.selectVersionByLabel(picker!, WIDGETS_API_REFERENCE_V1_LABEL);
241
232
  await page.waitForRedocTopicLoad();
242
233
 
243
- await browser.waitUntil(
244
- async () => (await browser.getUrl()).includes(`${BASE}/v1/widgets-api-reference`),
245
- { timeout: 15000, timeoutMsg: 'expected URL to contain /v1/widgets-api-reference' },
246
- );
234
+ await page.waitForUrlToContain(`${BASE}/v1/widgets-api-reference`);
247
235
  const apiInfo = await $('>>>div.api-info');
248
236
  expect(await apiInfo.getText()).toContain('1.0.0');
249
237
  });
@@ -270,21 +258,21 @@ describe('Topic-level versioning > URL resolution (markdown)', () => {
270
258
  page = new TopicVersionPage(`${BASE}/oauth.html`);
271
259
  page.open();
272
260
  await page.waitForMarkdownTopicLoad();
273
- expect(await (await $('>>>h1')).getText()).toEqual('OAuth 2.0');
261
+ expect(await (await page.getContentHeading()).getText()).toEqual('OAuth 2.0');
274
262
  });
275
263
 
276
264
  it('should serve the latest version at its versioned alias URL', async () => {
277
265
  page = new TopicVersionPage(`${BASE}/v2/oauth.html`);
278
266
  page.open();
279
267
  await page.waitForMarkdownTopicLoad();
280
- expect(await (await $('>>>h1')).getText()).toEqual('OAuth 2.0');
268
+ expect(await (await page.getContentHeading()).getText()).toEqual('OAuth 2.0');
281
269
  });
282
270
 
283
271
  it('should serve an older version at its versioned URL', async () => {
284
272
  page = new TopicVersionPage(`${BASE}/v1/oauth.html`);
285
273
  page.open();
286
274
  await page.waitForMarkdownTopicLoad();
287
- expect(await (await $('>>>h1')).getText()).toEqual('OAuth 1.0');
275
+ expect(await (await page.getContentHeading()).getText()).toEqual('OAuth 1.0');
288
276
  });
289
277
 
290
278
  it('should initialize the picker from the URL version', async () => {
@@ -293,7 +281,7 @@ describe('Topic-level versioning > URL resolution (markdown)', () => {
293
281
  await page.waitForMarkdownTopicLoad();
294
282
 
295
283
  const picker = await page.getSidebarPicker('OAuth');
296
- expect(await page.getSelectedVersionLabel(picker!)).toEqual("SU'26");
284
+ expect(await page.getSelectedVersionLabel(picker!)).toEqual(OAUTH_V1_LABEL);
297
285
  });
298
286
  });
299
287
 
@@ -333,18 +321,6 @@ describe('Topic-level versioning > single-version picker (read-only)', () => {
333
321
  expect(await page.isReadOnly(picker!)).toBeTruthy();
334
322
  expect(await page.getRedocVersionBanner()).toBeNull();
335
323
  });
336
-
337
- // fixture: Link Between Topics — already single version ('WI'26'). TODO: enable once
338
- // markdown topics render a read-only picker for single-version entries (the markdown
339
- // counterpart to the Redoc case above).
340
- it.skip('should render a read-only picker with no dropdown when a markdown topic has a single version', async () => {
341
- page = new TopicVersionPage(`${BASE}/internal-linking.html`);
342
- page.open();
343
- await page.waitForMarkdownTopicLoad();
344
- const picker = await page.getSidebarPicker('Link Between Topics');
345
- expect(await page.isReadOnly(picker!)).toBeTruthy();
346
- expect(await page.getMarkdownVersionBanner()).toBeNull();
347
- });
348
324
  });
349
325
 
350
326
  describe('Topic-level versioning > topics without a version picker', () => {
@@ -390,10 +366,7 @@ describe('Topic-level versioning > topics without a version picker', () => {
390
366
  await getStarted.click();
391
367
  await page.waitForMarkdownTopicLoad();
392
368
 
393
- await browser.waitUntil(
394
- async () => (await browser.getUrl()).includes(`${BASE}/get-started.html`),
395
- { timeout: 15000, timeoutMsg: 'expected URL to contain /get-started.html' },
396
- );
369
+ await page.waitForUrlToContain(`${BASE}/get-started.html`);
397
370
  expect(await browser.getUrl()).not.toContain('/v1/');
398
371
  });
399
372
  });
@@ -405,19 +378,20 @@ describe('Topic-level versioning > persistence on reload', () => {
405
378
  await page.waitForMarkdownTopicLoad();
406
379
 
407
380
  const picker = await page.getSidebarPicker('OAuth');
408
- await page.selectVersionByLabel(picker!, "SU'26");
381
+ await page.selectVersionByLabel(picker!, OAUTH_V1_LABEL);
409
382
  await page.waitForMarkdownTopicLoad();
410
383
 
411
384
  await browser.refresh();
412
385
  await page.waitForMarkdownTopicLoad();
413
386
 
414
387
  const pickerAfterReload = await page.getSidebarPicker('OAuth');
415
- expect(await page.getSelectedVersionLabel(pickerAfterReload!)).toEqual("SU'26");
416
- expect(await (await $('>>>h1')).getText()).toEqual('OAuth 1.0');
388
+ expect(await page.getSelectedVersionLabel(pickerAfterReload!)).toEqual(OAUTH_V1_LABEL);
389
+ expect(await (await page.getContentHeading()).getText()).toEqual('OAuth 1.0');
417
390
  expect(await browser.getUrl()).toContain(`${BASE}/v1/oauth.html`);
418
391
 
419
392
  const selections = await page.readSessionVersionSelections();
420
393
  expect(selections).not.toBeNull();
394
+ expect(selections![`${BASE}/oauth.html`]).toEqual('v1');
421
395
  });
422
396
  });
423
397