@salesforcedevs/sfdocs-e2e 1.0.12-e2e-topic-version-7 → 1.0.12-e2e-topic-version-8

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-7",
3
+ "version": "1.0.12-e2e-topic-version-8",
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,17 +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
- expect(await browser.getUrl()).toContain(`${BASE}/v1/oauth.html`);
51
+ expect(await (await page.getContentHeading()).getText()).toEqual('OAuth 1.0');
52
+ await page.waitForUrlToContain(`${BASE}/v1/oauth.html`);
43
53
  });
44
54
 
45
55
  it('should return to the canonical URL when the latest version is reselected', async () => {
@@ -48,13 +58,14 @@ describe('Topic-level versioning > versioned markdown topic', () => {
48
58
  await page.waitForMarkdownTopicLoad();
49
59
 
50
60
  const picker = await page.getSidebarPicker('OAuth');
51
- await page.selectVersionByLabel(picker!, "WI'26");
61
+ await page.selectVersionByLabel(picker!, OAUTH_V2_LABEL);
52
62
  await page.waitForMarkdownTopicLoad();
53
63
 
64
+ await page.waitForUrlToEndWith(`${BASE}/oauth.html`);
54
65
  const url = await browser.getUrl();
55
66
  expect(url.endsWith(`${BASE}/oauth.html`)).toBeTruthy();
56
67
  expect(url).not.toContain('/v2/');
57
- expect(await (await $('>>>h1')).getText()).toEqual('OAuth 2.0');
68
+ expect(await (await page.getContentHeading()).getText()).toEqual('OAuth 2.0');
58
69
  });
59
70
 
60
71
  it('should show the "Newer Version Available" banner when the version is not latest', async () => {
@@ -73,7 +84,7 @@ describe('Topic-level versioning > versioned markdown topic', () => {
73
84
  });
74
85
 
75
86
  describe('Topic-level versioning > versioned parent with versioned child subtree', () => {
76
- // 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).
77
88
  beforeEach(async () => {
78
89
  page = new TopicVersionPage(`${BASE}/android.html`);
79
90
  page.open();
@@ -83,16 +94,16 @@ describe('Topic-level versioning > versioned parent with versioned child subtree
83
94
  it('should render the picker on the parent and default to the latest version', async () => {
84
95
  const picker = await page.getSidebarPicker('Client SDKs');
85
96
  expect(picker).not.toBeNull();
86
- expect(await page.getSelectedVersionLabel(picker!)).toEqual("WI'26");
97
+ expect(await page.getSelectedVersionLabel(picker!)).toEqual(CLIENT_SDKS_V2_LABEL);
87
98
  });
88
99
 
89
100
  it('should switch the whole child subtree when the parent version changes', async () => {
90
101
  const picker = await page.getSidebarPicker('Client SDKs');
91
- await page.selectVersionByLabel(picker!, "SU'26");
102
+ await page.selectVersionByLabel(picker!, CLIENT_SDKS_V1_LABEL);
92
103
  await page.waitForMarkdownTopicLoad();
93
104
 
94
- expect(await browser.getUrl()).toContain(`${BASE}/v1/android.html`);
95
- 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');
96
107
 
97
108
  // Sibling child (iOS SDK) should also have moved to the v1 URL, not just this one.
98
109
  const iosItem = await page.getSidebarTreeItem('iOS SDK');
@@ -114,7 +125,7 @@ describe('Topic-level versioning > versioned parent with versioned child subtree
114
125
  await page.waitForMarkdownTopicLoad();
115
126
 
116
127
  const picker = await page.getSidebarPicker('Client SDKs');
117
- expect(await page.getSelectedVersionLabel(picker!)).toEqual("WI'26");
128
+ expect(await page.getSelectedVersionLabel(picker!)).toEqual(CLIENT_SDKS_V2_LABEL);
118
129
 
119
130
  const iosItem = await page.getSidebarTreeItem('iOS SDK');
120
131
  const iosTile = await page.getTreeItemTile(iosItem);
@@ -126,7 +137,7 @@ describe('Topic-level versioning > versioned parent with versioned child subtree
126
137
  });
127
138
 
128
139
  describe('Topic-level versioning > versioned parent with own content, subtopics and a spec subtopic', () => {
129
- // 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).
130
141
  beforeEach(async () => {
131
142
  page = new TopicVersionPage(`${BASE}/errors-and-rate-limits.html`);
132
143
  page.open();
@@ -136,42 +147,44 @@ describe('Topic-level versioning > versioned parent with own content, subtopics
136
147
  it('should render the picker and default to the latest version', async () => {
137
148
  const picker = await page.getSidebarPicker('Errors and Rate Limits');
138
149
  expect(picker).not.toBeNull();
139
- expect(await page.getSelectedVersionLabel(picker!)).toEqual("SP'26");
150
+ expect(await page.getSelectedVersionLabel(picker!)).toEqual(ERRORS_V2_LABEL);
140
151
  });
141
152
 
142
153
  it("should switch the parent's own page content when the version changes", async () => {
143
154
  const picker = await page.getSidebarPicker('Errors and Rate Limits');
144
- await page.selectVersionByLabel(picker!, "WI'25");
155
+ await page.selectVersionByLabel(picker!, ERRORS_V1_LABEL);
145
156
  await page.waitForMarkdownTopicLoad();
146
157
 
147
- expect(await (await $('>>>h1')).getText()).toEqual('Errors and Rate Limits (v1)');
148
- expect(await browser.getUrl()).toContain(`${BASE}/v1/errors-and-rate-limits.html`);
158
+ expect(await (await page.getContentHeading()).getText()).toEqual(
159
+ 'Errors and Rate Limits (v1)',
160
+ );
161
+ await page.waitForUrlToContain(`${BASE}/v1/errors-and-rate-limits.html`);
149
162
  });
150
163
 
151
164
  it('should switch the markdown subtopics when the version changes', async () => {
152
165
  const picker = await page.getSidebarPicker('Errors and Rate Limits');
153
- await page.selectVersionByLabel(picker!, "WI'25");
166
+ await page.selectVersionByLabel(picker!, ERRORS_V1_LABEL);
154
167
  await page.waitForMarkdownTopicLoad();
155
168
 
156
169
  const child = await page.getSidebarTreeItem('Common Error Codes');
157
170
  await child.click();
158
171
  await page.waitForMarkdownTopicLoad();
159
172
 
160
- expect(await (await $('>>>h1')).getText()).toEqual('Common Error Codes (v1)');
161
- expect(await browser.getUrl()).toContain(`${BASE}/v1/extra-child-a.html`);
173
+ expect(await (await page.getContentHeading()).getText()).toEqual('Common Error Codes (v1)');
174
+ await page.waitForUrlToContain(`${BASE}/v1/extra-child-a.html`);
162
175
  });
163
176
 
164
177
  it('should switch the spec (Redoc) subtopic to the matching version when the version changes', async () => {
165
178
  // Key cross-type cascade: parent v1 ⇒ the nested spec subtopic is v1 too.
166
179
  const picker = await page.getSidebarPicker('Errors and Rate Limits');
167
- await page.selectVersionByLabel(picker!, "WI'25");
180
+ await page.selectVersionByLabel(picker!, ERRORS_V1_LABEL);
168
181
  await page.waitForMarkdownTopicLoad();
169
182
 
170
183
  const child = await page.getSidebarTreeItem('Another Spec API');
171
184
  await child.click();
172
185
  await page.waitForRedocTopicLoad();
173
186
 
174
- expect(await browser.getUrl()).toContain(`${BASE}/v1/new-sample-api`);
187
+ await page.waitForUrlToContain(`${BASE}/v1/new-sample-api`);
175
188
  // v1's spec lacks the `GET /errors/{code}` operation that only v2 has — its absence
176
189
  // confirms the v1 spec asset loaded, since both versions share the same spec title.
177
190
  const getErrorCodeOperation = await $('a[href*="operation/getErrorCode"]');
@@ -186,7 +199,7 @@ describe('Topic-level versioning > versioned parent with own content, subtopics
186
199
  await page.waitForRedocTopicLoad();
187
200
 
188
201
  const redocPicker = await page.getRedocPicker();
189
- await page.selectVersionByLabel(redocPicker!, "WI'25");
202
+ await page.selectVersionByLabel(redocPicker!, ERRORS_V1_LABEL);
190
203
  await page.waitForRedocTopicLoad();
191
204
 
192
205
  page = new TopicVersionPage(`${BASE}/errors-and-rate-limits.html`);
@@ -194,7 +207,7 @@ describe('Topic-level versioning > versioned parent with own content, subtopics
194
207
  await page.waitForMarkdownTopicLoad();
195
208
 
196
209
  const parentPicker = await page.getSidebarPicker('Errors and Rate Limits');
197
- expect(await page.getSelectedVersionLabel(parentPicker!)).toEqual("WI'25");
210
+ expect(await page.getSelectedVersionLabel(parentPicker!)).toEqual(ERRORS_V1_LABEL);
198
211
  });
199
212
  });
200
213
 
@@ -210,15 +223,15 @@ describe('Topic-level versioning > standalone Redoc reference', () => {
210
223
  it('should render the Redoc version picker and default to the latest version', async () => {
211
224
  const picker = await page.getRedocPicker();
212
225
  expect(picker).not.toBeNull();
213
- expect(await page.getSelectedVersionLabel(picker!)).toEqual("SU'26");
226
+ expect(await page.getSelectedVersionLabel(picker!)).toEqual(WIDGETS_API_REFERENCE_V2_LABEL);
214
227
  });
215
228
 
216
229
  it('should switch the rendered spec when a different version is selected', async () => {
217
230
  const picker = await page.getRedocPicker();
218
- await page.selectVersionByLabel(picker!, "SP'26");
231
+ await page.selectVersionByLabel(picker!, WIDGETS_API_REFERENCE_V1_LABEL);
219
232
  await page.waitForRedocTopicLoad();
220
233
 
221
- expect(await browser.getUrl()).toContain(`${BASE}/v1/widgets-api-reference`);
234
+ await page.waitForUrlToContain(`${BASE}/v1/widgets-api-reference`);
222
235
  const apiInfo = await $('>>>div.api-info');
223
236
  expect(await apiInfo.getText()).toContain('1.0.0');
224
237
  });
@@ -245,21 +258,21 @@ describe('Topic-level versioning > URL resolution (markdown)', () => {
245
258
  page = new TopicVersionPage(`${BASE}/oauth.html`);
246
259
  page.open();
247
260
  await page.waitForMarkdownTopicLoad();
248
- expect(await (await $('>>>h1')).getText()).toEqual('OAuth 2.0');
261
+ expect(await (await page.getContentHeading()).getText()).toEqual('OAuth 2.0');
249
262
  });
250
263
 
251
264
  it('should serve the latest version at its versioned alias URL', async () => {
252
265
  page = new TopicVersionPage(`${BASE}/v2/oauth.html`);
253
266
  page.open();
254
267
  await page.waitForMarkdownTopicLoad();
255
- expect(await (await $('>>>h1')).getText()).toEqual('OAuth 2.0');
268
+ expect(await (await page.getContentHeading()).getText()).toEqual('OAuth 2.0');
256
269
  });
257
270
 
258
271
  it('should serve an older version at its versioned URL', async () => {
259
272
  page = new TopicVersionPage(`${BASE}/v1/oauth.html`);
260
273
  page.open();
261
274
  await page.waitForMarkdownTopicLoad();
262
- expect(await (await $('>>>h1')).getText()).toEqual('OAuth 1.0');
275
+ expect(await (await page.getContentHeading()).getText()).toEqual('OAuth 1.0');
263
276
  });
264
277
 
265
278
  it('should initialize the picker from the URL version', async () => {
@@ -268,7 +281,7 @@ describe('Topic-level versioning > URL resolution (markdown)', () => {
268
281
  await page.waitForMarkdownTopicLoad();
269
282
 
270
283
  const picker = await page.getSidebarPicker('OAuth');
271
- expect(await page.getSelectedVersionLabel(picker!)).toEqual("SU'26");
284
+ expect(await page.getSelectedVersionLabel(picker!)).toEqual(OAUTH_V1_LABEL);
272
285
  });
273
286
  });
274
287
 
@@ -308,18 +321,6 @@ describe('Topic-level versioning > single-version picker (read-only)', () => {
308
321
  expect(await page.isReadOnly(picker!)).toBeTruthy();
309
322
  expect(await page.getRedocVersionBanner()).toBeNull();
310
323
  });
311
-
312
- // fixture: Link Between Topics — already single version ('WI'26'). TODO: enable once
313
- // markdown topics render a read-only picker for single-version entries (the markdown
314
- // counterpart to the Redoc case above).
315
- it.skip('should render a read-only picker with no dropdown when a markdown topic has a single version', async () => {
316
- page = new TopicVersionPage(`${BASE}/internal-linking.html`);
317
- page.open();
318
- await page.waitForMarkdownTopicLoad();
319
- const picker = await page.getSidebarPicker('Link Between Topics');
320
- expect(await page.isReadOnly(picker!)).toBeTruthy();
321
- expect(await page.getMarkdownVersionBanner()).toBeNull();
322
- });
323
324
  });
324
325
 
325
326
  describe('Topic-level versioning > topics without a version picker', () => {
@@ -365,7 +366,7 @@ describe('Topic-level versioning > topics without a version picker', () => {
365
366
  await getStarted.click();
366
367
  await page.waitForMarkdownTopicLoad();
367
368
 
368
- expect(await browser.getUrl()).toContain(`${BASE}/get-started.html`);
369
+ await page.waitForUrlToContain(`${BASE}/get-started.html`);
369
370
  expect(await browser.getUrl()).not.toContain('/v1/');
370
371
  });
371
372
  });
@@ -377,19 +378,20 @@ describe('Topic-level versioning > persistence on reload', () => {
377
378
  await page.waitForMarkdownTopicLoad();
378
379
 
379
380
  const picker = await page.getSidebarPicker('OAuth');
380
- await page.selectVersionByLabel(picker!, "SU'26");
381
+ await page.selectVersionByLabel(picker!, OAUTH_V1_LABEL);
381
382
  await page.waitForMarkdownTopicLoad();
382
383
 
383
384
  await browser.refresh();
384
385
  await page.waitForMarkdownTopicLoad();
385
386
 
386
387
  const pickerAfterReload = await page.getSidebarPicker('OAuth');
387
- expect(await page.getSelectedVersionLabel(pickerAfterReload!)).toEqual("SU'26");
388
- 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');
389
390
  expect(await browser.getUrl()).toContain(`${BASE}/v1/oauth.html`);
390
391
 
391
392
  const selections = await page.readSessionVersionSelections();
392
393
  expect(selections).not.toBeNull();
394
+ expect(selections![`${BASE}/oauth.html`]).toEqual('v1');
393
395
  });
394
396
  });
395
397