Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 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
e51c11b
add base fixture
biocodeit Dec 3, 2025
e65ecf4
add index.ts for fixtures
biocodeit Dec 3, 2025
ee0db3f
import test from ./base
biocodeit Dec 3, 2025
529d31b
move preheader and prevariable to api fixture from collection fixture
biocodeit Dec 3, 2025
36b0db2
refactor code, add helper function to reduce redundancy
biocodeit Dec 3, 2025
45f1f50
move common code into fixture -make preheaders, prevariables fixtures
biocodeit Dec 3, 2025
628ea53
refactor to import from index.ts and remove page.goto
biocodeit Dec 3, 2025
eecc41c
move the throtle logic from basepage to base fixture
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.

28 changes: 24 additions & 4 deletions e2e/fixtures/api.fixture.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,36 @@
import {test as base} from '@playwright/test'
import {test as base} from './base.fixture'
import { APImodel } from '../object-models/api-model'

interface MyFixtures {
api : APImodel
apiReq : APImodel,
preHeaders : void,
preVariables : void
}


export const test = base.extend<MyFixtures>(
{
api : async({page},use) => {
apiReq : async({page},use) => {
use(new APImodel(page))
},
preVariables : async({page, apiReq},use) => {
await apiReq.chainVariableAdd('chainVar1', 'val1')
await apiReq.chainVariableAdd('chainVar2', 'val2')
await apiReq.scriptVariableAdd('scriptVar1', 'val1')
await apiReq.scriptVariableAdd('scriptVar2', 'val2')
await use()
},
preHeaders : async ({page, apiReq},use) => {
const[name1, name2, name3] = ['author1', 'author2','author3']
const[value1, value2, value3] = ['val1', 'val2', 'val3']
await apiReq.fillHeader(name1, value1)
await apiReq.fillHeader(name2, value2)
await apiReq.fillHeader(name3, value3)
await use()
}
})
}
)



export {expect} from '@playwright/test'
27 changes: 27 additions & 0 deletions e2e/fixtures/base.fixture.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import {test as base, type Page} from '@playwright/test'


export const test = base.extend<{},{throtle:void}>({
throtle : [ async({},use) => {
console.log('!!using new worker!')
use()

}, {scope:'worker'}],

page : async({page},use) => {
if(process.env.THROTLE) {
(async () => {
const context = await page.context()
const cdpSession = await context.newCDPSession(page);
await cdpSession.send('Emulation.setCPUThrottlingRate', { rate: 3 });

})()
}
await page.goto('/')
await use(page)
},


})

export {expect, type Page} from '@playwright/test'
5 changes: 1 addition & 4 deletions e2e/fixtures/chain.fixtures.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {test as base } from '@playwright/test'
import {test as base } from './base.fixture'
import {ChainModel} from '../object-models/chain-object'

interface myFixtures {
Expand All @@ -9,8 +9,6 @@ interface myFixtures {
export const test = base.extend<myFixtures>
({
singleChain : async ({page},use) => {
// 1. go to page
await page.goto('/')
// 2. add new chain
const chain = new ChainModel(page)
await chain.addNewChain('User Chain')
Expand All @@ -24,7 +22,6 @@ export const test = base.extend<myFixtures>
},

multiChain : async({page},use) => {
await page.goto('/')
const chain = new ChainModel(page)
for(let i=1; i<11; i++) {
await chain.addNewChain(`User Chain ${i}`)
Expand Down
33 changes: 33 additions & 0 deletions e2e/fixtures/collection.fixture.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import {test as base, Page } from '../fixtures/base.fixture'
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: Page,
preVariables : void,
preHeaders : void
}>
({
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({page, collection, apiReq},use) => {
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.

7 changes: 7 additions & 0 deletions e2e/fixtures/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { mergeTests } from "@playwright/test";
import {test as apiTest} from "./api.fixture"
import {test as chainTest} from "./chain.fixtures"
import {test as collectionTest} from "./collection.fixture"

export const test = mergeTests(apiTest, chainTest, collectionTest)
export {expect} from '@playwright/test'
22 changes: 11 additions & 11 deletions e2e/object-models/BasePage.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,22 @@
import {type Page, Locator} from '@playwright/test'


import { type Page, Locator } from '@playwright/test'

export class BasePage {
constructor(protected page:Page) {}
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' })
}
}
Loading