Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
96b2667
Add save test script to collection database
biocodeit Nov 27, 2025
317df94
rename collection fixture
biocodeit Nov 27, 2025
4a486a8
rename collection fixture
biocodeit Nov 28, 2025
754058b
add environment model to collection fixture
biocodeit Nov 28, 2025
0df5736
redundant remove collection.ts fixture due to renaming
biocodeit Nov 28, 2025
29ebdb0
add test script to api model
biocodeit Nov 28, 2025
f72d519
add env-setting model
biocodeit Nov 28, 2025
3adbcce
add a complete user project
biocodeit Nov 28, 2025
27fdc80
resolve bugs after previous env model changes
biocodeit Nov 28, 2025
04f8988
renamed the mini-project to complete-user-login
biocodeit Nov 28, 2025
ee64242
fix: prevent crash when entering invalid URLs in request builder, fix…
Dancode-188 Nov 27, 2025
efad928
refactor mini project
biocodeit Nov 28, 2025
3cdb836
Merge pull request #1 from Dancode-188/main
biocodeit Nov 28, 2025
61d68e3
add cpu throttle to check for flaky test
biocodeit Nov 28, 2025
9761164
repair locator syntax
biocodeit Nov 29, 2025
523309b
add 'detached' instead of 'hidden' for save collection div
biocodeit Nov 29, 2025
1255d47
add network idle before parsing api response
biocodeit Nov 29, 2025
c038307
rename files , spell mistake
biocodeit Nov 30, 2025
23d2fc1
refactor after renaming fixture files
biocodeit Dec 1, 2025
f80a821
deleted redundant collection fixture file
biocodeit Dec 1, 2025
7f25fdc
add request and options sections in basePage
biocodeit Nov 29, 2025
b3a977d
add option to select the request from selection before sending
biocodeit Nov 29, 2025
e5f1985
add environment select test
biocodeit Nov 30, 2025
113b868
add header section to basepage model
biocodeit Nov 30, 2025
e069607
add request assister helper model
biocodeit Nov 30, 2025
5829b2e
add complete test for request builder
biocodeit Dec 3, 2025
7783859
refactoring after rebase
biocodeit Dec 3, 2025
08e852d
change environemt select locator
biocodeit Dec 3, 2025
786a2fe
add nth(0) instead of first()
biocodeit Dec 3, 2025
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
30 changes: 0 additions & 30 deletions e2e/basic-workflow.spec.ts

This file was deleted.

32 changes: 32 additions & 0 deletions e2e/fixtures/collection.fixture.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import {test as base} from '@playwright/test'
import { CollectionModel } from '../object-models/collection-model'
import { APImodel } from '../object-models/api-model'
import { EnvSettings } from '../object-models/environment-setting.model'

export const test = base.extend<{
collection: CollectionModel,
apiReq: APImodel,
envSetup : EnvSettings,
singleCollection: any
}>
({
collection : async({page}, use) => {
await use(new CollectionModel(page))
},
apiReq : async ({page},use) => {
await use(new APImodel(page))
},
envSetup: async({page},use) => {
use(new EnvSettings(page))
},
singleCollection : async({collection, apiReq, page},use) => {
await page.goto('/')
await collection.createCollection('User Collection')
await apiReq.get('https://jsonplaceholder.typicode.com/todos/1')
await collection.saveToCollection('Req 1', 'User Collection')
await use(page)
}

})

export { expect} from '@playwright/test'
15 changes: 0 additions & 15 deletions e2e/fixtures/collection.ts

This file was deleted.

28 changes: 18 additions & 10 deletions e2e/object-models/BasePage.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,30 @@
import {type Page, Locator} from '@playwright/test'
import { type Page, Locator } from '@playwright/test'

export class BasePage {
constructor(protected page: Page) {
if (process.env.THROTLE) {
(async () => {
const context = this.page.context();
const cdpSession = await context.newCDPSession(this.page);
await cdpSession.send('Emulation.setCPUThrottlingRate', { rate: 6 });

})()
}
}

export class BasePage {
constructor(protected page:Page) {}
optionSection: Locator = this.page.locator('#_R_jklrlb_')
reqBuilderMain: Locator = this.page.locator('#_R_5klrlb_')
topHeader: Locator = this.page.getByRole('banner')

protected button(btnName: string): Locator
{
return this.page.getByRole('button', {name: btnName})
protected button(btnName: string): Locator {
return this.page.getByRole('button', { name: btnName })
}

protected fillBlock (input: string): Locator
{
protected fillBlock(input: string): Locator {
return this.page.getByPlaceholder(input)
}

protected async clearall(locator: Locator)
{
protected async clearall(locator: Locator) {
await locator.press('Control+A')
await locator.clear()
}
Expand Down
74 changes: 41 additions & 33 deletions e2e/object-models/api-model.ts
Original file line number Diff line number Diff line change
@@ -1,63 +1,71 @@
import {type Page, type Locator} from '@playwright/test'
import { BasePage } from './BasePage'
import { ReqHelpers } from './request-assiters.model'

export class APImodel extends BasePage {
export class APImodel extends ReqHelpers {

constructor(page:Page)
{super(page)
}

fillUrl : Locator = this.page.getByPlaceholder('https://api.example.com/endpoint')
sendBtn : Locator = this.page.getByRole('button', {name:'Send'})
responseBody : Locator = this.page.locator('div').filter({hasText:'Body'})
.filter({hasText:'Compare'}).last()
.getByRole('presentation')
reqType : Locator = this.page.getByRole('combobox')
reqBody : Locator = this.page.locator('div',{hasText:'Request Body (JSON)',
has: this.page.getByRole('presentation')})
.last()
.getByRole('textbox')
reqMainHeading : Locator = this.reqBuilderMain.getByRole('heading', {name: 'Request Builder'})

fillUrl : Locator = this.reqBuilderMain.getByPlaceholder('https://api.example.com/endpoint')
sendBtn : Locator = this.reqBuilderMain.getByRole('button', {name:'Send'})
responseSec : Locator = this.page.locator('#_R_9klrlb_')
responseBody : Locator = this.responseSec.getByRole('presentation')
reqType : Locator = this.reqBuilderMain.getByRole('combobox')
reqBodySection : Locator = this.reqBuilderMain.locator('div',{hasText:'Headers'}).getByRole('button',{name: 'Body'})
reqBody : Locator = this.reqBuilderMain.locator('div').filter({has: this.page.getByRole('presentation')})
.filter({hasText:'Request Body (JSON)'}).last()
.getByRole('textbox')


async get(url:string):Promise<string>
{
await this.fillUrl.fill(url)

await this.reqType.selectOption('GET')
await this.sendBtn.click()
return await this.getResponseResult()
}

async post(url: string, data : string)
{
await this.fillUrl.fill(url)
await this.reqType.selectOption('POST')
await this.fillRequestBody(data)
await this.sendBtn.click()
return await this.getResponseResult()
}
{await this.apiwrap('POST', url, data)}

async patch(url: string, data: string)
{
await this.fillUrl.fill(url)
await this.reqType.selectOption('PATCH')
await this.fillRequestBody(data)
await this.sendBtn.click()
return await this.getResponseResult()
}
{await this.apiwrap('PATCH', url, data)}

private async fillRequestBody (data: string)
{
private async fillRequestBody (data: string) {
await this.clearall(this.reqBody)
await this.reqBody.fill(data)
}

private async getResponseResult()
{
await this.page.waitForLoadState('domcontentloaded')
async getResponseResult(collectionName?:string, reqName?:string) {
if(collectionName && reqName){
const neededReq = await this.optionSection.getByRole('button',{name: reqName})
if (await neededReq.isVisible()) {
await neededReq.click()
} else {
await this.selectReq(collectionName, reqName)
}
}
await this.sendBtn.click()
await this.page.waitForLoadState('networkidle')
await this.responseBody.locator('.view-line').last().textContent()
let result = await this.responseBody.textContent()
result = result.replace(/\u00A0/g, ' ')
return result
}

private async apiwrap(method:string, url:string, data: string) {{
await this.fillUrl.fill(url)
await this.reqType.selectOption(method)
await this.reqBodySection.click()
await this.fillRequestBody(data)
}
}


async selectReq(collName:string, reqName:string) {
await this.optionSection.getByRole('button',{name:collName}).click()
await this.optionSection.getByRole('button',{name: reqName}).click()
}
}
6 changes: 3 additions & 3 deletions e2e/object-models/collection-model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ export class CollectionModel extends BasePage {
constructor(page: Page) {
super(page)
}

saveToCollectionBtn : Locator = this.page.getByTitle('Save to collection')

async createCollection(colName: string)
{
Expand All @@ -19,13 +19,13 @@ export class CollectionModel extends BasePage {

async saveToCollection(postNam: string, collNam: string)
{
await this.page.getByTitle('Save to collection').click()
await this.saveToCollectionBtn.click()
// get the collection block
const collDiv = await this.page.locator('div')
.filter({ hasText: 'Request Name (optional)' })
.filter({ hasText: 'Select Collection' }).last()
await collDiv.getByRole('textbox').fill(postNam)
await collDiv.getByRole('button').filter({ hasText: collNam }).click()
await collDiv.getByLabel('Request Name (optional)').waitFor({ state: 'hidden' })
await collDiv.waitFor({ state: 'detached' })
}
}
47 changes: 47 additions & 0 deletions e2e/object-models/environment-setting.model.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import { BasePage} from "./BasePage";
import { type Page, Locator } from "@playwright/test";

export class EnvSettings extends BasePage {
constructor(page:Page) {
super(page)
}
envSec : Locator = this.page.getByRole('button',{name:'Environment'})
envDiv : Locator = this.page.locator('//div')
.filter({has: this.envSec})
.filter({has: this.page
.getByRole('heading',{name:'Environment'})}).last()
createNewEnvBtn : Locator = this.envDiv.getByRole('button', {name:'+ New'})
saveNewEnvBtn : Locator = this.envDiv.getByRole('button',{name: 'Create'})
envNameInput : Locator = this.envDiv.getByPlaceholder('Environment name')
addEnvVarBtn : Locator = this.envDiv.getByRole('button', {name:'+ Add'})
envVarNameInput : Locator = this.envDiv.getByPlaceholder('Variable name', {exact: true})
envVarValueInput : Locator = this.envDiv.getByPlaceholder('Value')
envVarSaveBtn : Locator = this.envDiv.getByTitle('Add variable')
envVarSaveConfirm : Locator = this.envDiv.getByRole('button', {name: 'Save'})

async createNewEnv(envName:string) {
await this.envSec.click()
await this.createNewEnvBtn.click()
await this.envNameInput.fill(envName)
await this.saveNewEnvBtn.click()
}

async addEnvVariable(envName:string , varName:string, varValue: string) {
await this.envDiv.locator('div', {hasText: envName})
.filter({hasText: 'Edit'}).last()
.getByRole('button', {name: 'Edit'}).click()
await this.addEnvVarBtn.click()
await this.envVarNameInput.fill(varName)
await this.envVarValueInput.fill(varValue)
await this.envVarSaveBtn.click()
await this.envVarSaveConfirm.click()
}

async selectEnvironment(envName:string) {
await this.page.waitForLoadState('domcontentloaded')
await this.topHeader.locator('button:right-of(h1:has-text("RestBolt"))').nth(0).click()
await this.topHeader.getByRole('button',{name:envName})
.last()
.click()
}
}
Loading