Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
54 commits
Select commit Hold shift + click to select a range
e3b2496
COnflicts resolved
Jun 17, 2026
085fba1
BRU-2571 Overview revamp changes
Jun 17, 2026
3eb91b6
BRU-2571 Theme color changes
Jun 17, 2026
2a38ca5
BRU-2571 Theme color changes
Jun 17, 2026
2008212
BRU-2571 E2E test case fix
Jun 17, 2026
10663ee
BRU-2571 Overview revamp changes
Jun 18, 2026
4742909
BRU-3571 Removed the border bottom line
Jun 18, 2026
d6cd48b
BRU-3571 Overview test-id revamp changes
Jun 18, 2026
c9c75b7
BRU-3571 mobile responsive changes
Jun 19, 2026
54ec45e
BRU-3571 Comments addressed
Jun 22, 2026
c8b22db
BRU-3571 Comments addressed
Jun 22, 2026
14d489a
E2E test folder changes
Jun 22, 2026
e8ad453
E2E test folder changes
Jun 22, 2026
4707200
BRU-3571 E2E playwright test cases changes
Jun 22, 2026
704993e
feat:Overview E2E test case updation
Jun 23, 2026
2b15833
feat:Overview code refactoring
Jun 23, 2026
520afa2
feat:Overview code refactoring
Jun 23, 2026
d070f28
Comments addressed
Jun 24, 2026
a2fbaf8
Comments addressed
Jun 24, 2026
69468c5
Comments addressed
Jun 24, 2026
a0a8859
Comments addressed
Jun 24, 2026
58a3dc7
Comments addressed
Jun 24, 2026
4d614fb
Comments addressed
Jun 24, 2026
6dc8525
Comments addressed
Jun 24, 2026
d8ee950
Request page redesign changes
Jun 22, 2026
97d4374
Execution context UI changes
Jun 23, 2026
725e31d
feat: UI changes for variables, tests, and asserts
Jun 24, 2026
f73c46a
Comments addressed
Jun 24, 2026
58b7622
Feat: Added scripts page
Jun 24, 2026
3140af4
Feat: BRU-3569 Request page changes
Jun 24, 2026
dd06621
Feat: BRU-3569 Request page changes
Jun 24, 2026
c0acc36
Feat: BRU-3569 Request page code refactoring
Jun 24, 2026
b0a00b4
Feat: BRU-3569 Request page code refactoring
Jun 24, 2026
6805070
Feat: BRU-3569 Request page code refactoring
Jun 24, 2026
b0bbd89
Feat: BRU-3569 Request page code refactoring
Jun 25, 2026
f946a72
Feat: BRU-3569 Request page E2E refactoring
Jun 25, 2026
ba1cbf7
Feat: BRU-3569 Request page E2E refactoring
Jun 25, 2026
6ecf598
Feat: BRU-3569 Request page E2E refactoring
Jun 25, 2026
c5b75e3
Feat: BRU-3569 Added unsupported request type page
Jun 25, 2026
dfd1b9e
Conflicts resolved
Jun 25, 2026
d3f3636
Feat: BRU-3569 Code refactoring
Jun 25, 2026
64da4a9
Feat: BRU-3569 Code refactoring
Jun 25, 2026
002afdb
Feat: BRU-3569 Code refactoring
Jun 25, 2026
78bd3fc
Feat: BRU-3569 Code refactoring
Jun 25, 2026
547f28a
Feat: BRU-3569 Code refactoring
Jun 25, 2026
3bfb707
Feat: BRU-3569 Code refactoring
Jun 26, 2026
5250bed
Feat: BRU-3569 Code refactoring
Jun 26, 2026
68010d5
Feat: BRU-3569 Code refactoring
Jun 26, 2026
0cdf60b
Conflicts resolved
Jun 26, 2026
e56dd6d
Conflicts resolved
Jun 26, 2026
22f18d1
Code refactoring
Jun 26, 2026
6e70b37
Code refactoring
Jun 26, 2026
13d189e
Code refactoring
Jun 26, 2026
aa03ead
Code refactoring
Jun 27, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 30 additions & 6 deletions packages/oc-docs/e2e/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@ Two rules shape every test here:
|------|------|
| Collection Overview — version/name, stat counts, environments, configuration | `tests/overview/overview.spec.ts` |
| Overview documentation — rendered Markdown | `tests/overview/overview-documentation.spec.ts` |
| Request page — details (breadcrumb, title, method/URL, description, params, auth, code snippet) | `tests/request/request-details.spec.ts` |
| Request page — Examples | `tests/request/request-examples.spec.ts` |
| Request page — Execution Context (scripts, variables, asserts, tests) | `tests/request/request-execution-context.spec.ts` |
| Script page — title, breadcrumb, source code | `tests/script/script.spec.ts` |
| Light/dark theme switch | `tests/theming/theme-toggle.spec.ts` |

## Running the tests
Expand All @@ -36,27 +40,47 @@ e2e/
├── tests/ # the tests, grouped by feature
│ ├── overview/overview.spec.ts
│ ├── overview/overview-documentation.spec.ts
│ ├── request/request-details.spec.ts
│ ├── request/request-examples.spec.ts
│ ├── request/request-execution-context.spec.ts
│ ├── script/script.spec.ts
│ └── theming/theme-toggle.spec.ts
├── pages/ # one "page object" per screen
│ ├── base.page.ts # shared navigation (goto, reload)
│ └── overview.page.ts # OverviewPage — composes its overview/ sections
│ ├── overview.page.ts # OverviewPage — composes its overview/ sections
│ ├── request.page.ts # RequestPage — composes its request/ sections
│ └── script.page.ts # ScriptPage — breadcrumb, title, source code
├── components/ # reusable pieces
│ ├── base.component.ts # shared base — every component has a `root`
│ ├── markdown.component.ts # any block of rendered Markdown
│ ├── secret-value.component.ts # a masked value with a reveal toggle
│ ├── theme-toggle.component.ts # the light/dark switch
│ └── overview/ # sections specific to the Overview page
│ ├── header-section.component.ts
│ ├── stats-section.component.ts
│ ├── environments-section.component.ts
│ └── configuration-section.component.ts
│ ├── sidebar.component.ts # the navigation tree (open a request/script)
│ ├── breadcrumb.component.ts # the "folder › folder › page" trail
│ ├── overview/ # sections specific to the Overview page
│ │ ├── header-section.component.ts
│ │ ├── stats-section.component.ts
│ │ ├── environments-section.component.ts
│ │ └── configuration-section.component.ts
│ ├── request/ # sections specific to the Request page
│ │ ├── url-bar.component.ts
│ │ ├── code-snippet.component.ts
│ │ ├── examples.component.ts
│ │ └── execution-context.component.ts
│ └── script/ # sections specific to the Script page
│ └── script-content.component.ts
├── playwright/ # the test harness
│ ├── pages.fixture.ts # defines the fixtures
│ └── index.ts # merges them; the single import for specs
├── config/app.config.ts # base URL + how to start the app
└── tsconfig.json # TypeScript settings for this folder
```

The Request and Script pages have no URL of their own, so their page objects reach
them by navigating the **sidebar** — `requestPage.open(['billing', 'customers', 'Get
All Customers'])` clicks down the folder trail and waits for the page to render. The
reusable `sidebar` and `breadcrumb` components are shared by both pages.

## The three building blocks

**Page objects** (`pages/`) describe a whole screen. They own navigation (`goto`) and
Expand Down
4 changes: 0 additions & 4 deletions packages/oc-docs/e2e/components/base.component.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,6 @@
import type { Page, Locator } from '@playwright/test';

export abstract class BaseComponent {
/**
* The element this component is scoped to. Section components receive their
* container; page-wide controls omit it and default to the whole page.
*/
readonly root: Locator;

constructor(protected readonly page: Page, root?: Locator) {
Expand Down
17 changes: 17 additions & 0 deletions packages/oc-docs/e2e/components/breadcrumb.component.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import type { Locator, Page } from '@playwright/test';
import { BaseComponent } from './base.component';

export class BreadcrumbComponent extends BaseComponent {
readonly current: Locator;
readonly segments: Locator;

constructor(page: Page, testId: string) {
super(page, page.getByTestId(testId));
this.current = page.getByTestId(`${testId}-current`);
this.segments = page.getByTestId(`${testId}-segment`);
}

segment(name: string): Locator {
return this.segments.filter({ hasText: name });
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,22 +5,14 @@ import { SecretValueComponent } from '../secret-value.component';
export class ConfigurationSection extends BaseComponent {
readonly root = this.page.getByTestId('collection-config');

Comment thread
sachin-bruno marked this conversation as resolved.
readonly copyButton = this.root.getByTestId('collection-config-copy').first();
readonly copyButton = this.root.getByTestId('collection-config-tests-copy');

readonly secret = new SecretValueComponent(this.page, 'collection-config-secret');
readonly secret = new SecretValueComponent(this.page, 'collection-config-auth-secret');

subHeading(name: string): Locator {
return this.root.getByTestId('collection-config-subheading').filter({ hasText: name });
}

row(key: string): Locator {
return this.root.getByTestId('collection-config-row').filter({ hasText: key });
}

rowValue(key: string): Locator {
return this.row(key).getByTestId('collection-config-row-value');
}

async copyToClipboard(): Promise<void> {
await this.copyButton.click();
}
Expand Down
16 changes: 16 additions & 0 deletions packages/oc-docs/e2e/components/request/code-snippet.component.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import type { Locator } from '@playwright/test';
import { BaseComponent } from '../base.component';

export class CodeSnippetComponent extends BaseComponent {
readonly root = this.page.getByTestId('request-code-snippet');

readonly code = this.root.locator('code');

languageTab(language: string): Locator {
return this.root.getByTestId(`code-snippet-tab-${language}`);
}

async selectLanguage(language: string): Promise<void> {
await this.languageTab(language).click();
}
}
36 changes: 36 additions & 0 deletions packages/oc-docs/e2e/components/request/examples.component.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import type { Locator } from '@playwright/test';
import { BaseComponent } from '../base.component';

export class ExamplesComponent extends BaseComponent {
readonly root = this.page.getByTestId('request-examples');

readonly items = this.root.getByTestId('example-card');

example(name: string): Locator {
return this.items.filter({ hasText: name });
}

statusCode(name: string): Locator {
return this.example(name).getByTestId('example-status');
}

requestBody(name: string): Locator {
return this.example(name).getByTestId('example-request-pane-body');
}

responseBody(name: string): Locator {
return this.example(name).getByTestId('example-response-pane-body');
}

async open(name: string): Promise<void> {
await this.example(name).getByTestId('example-toggle').click();
}

async selectRequestTab(name: string, tab: string): Promise<void> {
await this.example(name).getByTestId(`example-request-pane-tab-${tab}`).click();
}

async selectResponseTab(name: string, tab: string): Promise<void> {
await this.example(name).getByTestId(`example-response-pane-tab-${tab}`).click();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import type { Locator } from '@playwright/test';
import { BaseComponent } from '../base.component';

export class ExecutionContextComponent extends BaseComponent {
readonly root = this.page.getByTestId('execution-context');

readonly scripts = this.root.getByTestId('execution-context-scripts');
readonly variables = this.root.getByTestId('execution-context-variables');
readonly asserts = this.root.getByTestId('execution-context-asserts');
readonly tests = this.root.getByTestId('execution-context-tests');

script(label: string): Locator {
return this.scripts.getByText(label);
}

variable(name: string): Locator {
return this.variables.getByText(name, { exact: true });
}

assertion(text: string): Locator {
return this.asserts.getByText(text);
}

testCase(name: string): Locator {
return this.tests.getByText(name);
}
}
9 changes: 9 additions & 0 deletions packages/oc-docs/e2e/components/request/url-bar.component.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { BaseComponent } from '../base.component';

export class RequestUrlBarComponent extends BaseComponent {
readonly root = this.page.getByTestId('request-url-bar');

readonly method = this.root.getByTestId('request-method');
readonly url = this.root.getByTestId('request-url');
readonly tryButton = this.root.getByTestId('request-try-button');
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { BaseComponent } from '../base.component';

export class ScriptContentComponent extends BaseComponent {
readonly root = this.page.getByTestId('script-code');

readonly code = this.root.locator('code');

readonly copyButton = this.root.getByTestId('script-code-copy');
}
16 changes: 16 additions & 0 deletions packages/oc-docs/e2e/components/sidebar.component.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import type { Locator } from '@playwright/test';
import { BaseComponent } from './base.component';

export class SidebarComponent extends BaseComponent {
readonly items = this.page.getByTestId('sidebar-item');

item(name: string): Locator {
return this.items.filter({ hasText: name });
}

async open(trail: string[]): Promise<void> {
for (const name of trail) {
await this.item(name).first().click();
}
}
}
2 changes: 1 addition & 1 deletion packages/oc-docs/e2e/pages/overview.page.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { MarkdownComponent } from '../components/markdown.component';
import { HeaderSection } from '../components/overview/header.component';
import { StatsSection } from '../components/overview/collection-stats.component';
import { EnvironmentsSection } from '../components/overview/environments.component';
import { ConfigurationSection } from '../components/overview/collection-configuration.component.';
import { ConfigurationSection } from '../components/overview/collection-configuration.component';

export class OverviewPage extends BasePage {
readonly root = this.page.getByTestId('overview');
Expand Down
32 changes: 32 additions & 0 deletions packages/oc-docs/e2e/pages/request.page.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import type { Locator } from '@playwright/test';
import { BasePage } from './base.page';
import { SidebarComponent } from '../components/sidebar.component';
import { BreadcrumbComponent } from '../components/breadcrumb.component';
import { RequestUrlBarComponent } from '../components/request/url-bar.component';
import { CodeSnippetComponent } from '../components/request/code-snippet.component';
import { ExamplesComponent } from '../components/request/examples.component';
import { ExecutionContextComponent } from '../components/request/execution-context.component';

export class RequestPage extends BasePage {
readonly root = this.page.getByTestId('request-page');

readonly sidebar = new SidebarComponent(this.page);
readonly breadcrumb = new BreadcrumbComponent(this.page, 'request-breadcrumb');
readonly title = this.page.getByTestId('request-title');
readonly urlBar = new RequestUrlBarComponent(this.page);
readonly description = this.page.getByTestId('request-description');
readonly codeSnippet = new CodeSnippetComponent(this.page);
readonly examples = new ExamplesComponent(this.page);
readonly executionContext = new ExecutionContextComponent(this.page);

async open(trail: string[]): Promise<void> {
await this.navigate('/');
await this.sidebar.open(trail);
await this.root.waitFor({ state: 'visible' });
}

section(label: string): Locator {
const slug = label.toLowerCase().replace(/\s+/g, '-');
return this.page.getByTestId(`request-section-${slug}`);
}
}
19 changes: 19 additions & 0 deletions packages/oc-docs/e2e/pages/script.page.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { BasePage } from './base.page';
import { SidebarComponent } from '../components/sidebar.component';
import { BreadcrumbComponent } from '../components/breadcrumb.component';
import { ScriptContentComponent } from '../components/script/script-content.component';

export class ScriptPage extends BasePage {
readonly root = this.page.getByTestId('script-page');

readonly sidebar = new SidebarComponent(this.page);
readonly breadcrumb = new BreadcrumbComponent(this.page, 'script-breadcrumb');
readonly title = this.page.getByTestId('script-title');
readonly content = new ScriptContentComponent(this.page);

async open(trail: string[]): Promise<void> {
await this.navigate('/');
await this.sidebar.open(trail);
await this.root.waitFor({ state: 'visible' });
}
}
18 changes: 18 additions & 0 deletions packages/oc-docs/e2e/pages/unsupported-request.page.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { BasePage } from './base.page';
import { SidebarComponent } from '../components/sidebar.component';
import { BreadcrumbComponent } from '../components/breadcrumb.component';

export class UnsupportedRequestPage extends BasePage {
readonly root = this.page.getByTestId('unsupported-request');

readonly sidebar = new SidebarComponent(this.page);
readonly breadcrumb = new BreadcrumbComponent(this.page, 'unsupported-request-breadcrumb');
readonly title = this.page.getByTestId('unsupported-request-title');
readonly message = this.page.getByTestId('unsupported-request-empty');

async open(trail: string[]): Promise<void> {
await this.navigate('/');
await this.sidebar.open(trail);
await this.root.waitFor({ state: 'visible' });
}
}
27 changes: 21 additions & 6 deletions packages/oc-docs/e2e/playwright/pages.fixture.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
import { test as base } from '@playwright/test';
import { OverviewPage } from '../pages/overview.page';
import { PageHeaderComponent } from '../components/layout/page-header.component';
import { RequestPage } from '../pages/request.page';
import { ScriptPage } from '../pages/script.page';
import { UnsupportedRequestPage } from '../pages/unsupported-request.page';
import { SidebarComponent } from '../components/sidebar.component';
import { ThemeToggleComponent } from '../components/theme-toggle.component';
import { PageHeaderComponent } from '../components/layout/page-header.component';

/**
* Registers the page objects and shared components as Playwright fixtures, so a
* spec receives a ready instance by destructuring (e.g. `{ pageHeader }`) and
* calls `pageHeader.brandName` directly instead of constructing it.
*/
type Fixtures = {
overviewPage: OverviewPage;
requestPage: RequestPage;
scriptPage: ScriptPage;
unsupportedRequestPage: UnsupportedRequestPage;
sidebar: SidebarComponent;
pageHeader: PageHeaderComponent;
themeToggle: ThemeToggleComponent;
};
Expand All @@ -18,6 +21,18 @@ export const test = base.extend<Fixtures>({
overviewPage: async ({ page }, use) => {
await use(new OverviewPage(page));
},
requestPage: async ({ page }, use) => {
await use(new RequestPage(page));
},
scriptPage: async ({ page }, use) => {
await use(new ScriptPage(page));
},
unsupportedRequestPage: async ({ page }, use) => {
await use(new UnsupportedRequestPage(page));
},
sidebar: async ({ page }, use) => {
await use(new SidebarComponent(page));
},
pageHeader: async ({ page }, use) => {
await use(new PageHeaderComponent(page));
},
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
import { test, expect } from '../../playwright';

// The Markdown rendered inside the Overview's "Overview" (documentation) section.

test.describe('Overview documentation (rendered Markdown)', () => {
test.beforeEach(async ({ overviewPage }) => {
await overviewPage.goto();
Expand Down
Loading
Loading