-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
2 changed files
with
282 additions
and
281 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,235 @@ | ||
import { expect, type Locator, type Page } from "@playwright/test"; | ||
|
||
export class RSSBokmarkrPage { | ||
readonly pageURL: string; | ||
readonly page: Page; | ||
readonly urlInput: Locator; | ||
readonly addURLButton: Locator; | ||
readonly deleteURLButton: Locator; | ||
readonly loginFormTitle: Locator; | ||
readonly loginUsernameField: Locator; | ||
readonly loginPasswordField: Locator; | ||
readonly saveURLsButton: Locator; | ||
readonly logoutButton: Locator; | ||
readonly subscribeModalButton: Locator; | ||
readonly subscribeFormButton: Locator; | ||
readonly subscribeEmailField: Locator; | ||
readonly unsubscribeButton: Locator; | ||
readonly loginModalButton: Locator; | ||
readonly loginFormButton: Locator; | ||
readonly skeletonLoading: Locator; | ||
|
||
private loginResonse?: any = undefined; | ||
|
||
readonly sessionKey = "session_id"; | ||
|
||
constructor(pageURL: string, page: Page) { | ||
this.pageURL = pageURL; | ||
this.page = page; | ||
this.urlInput = page.getByPlaceholder("https://overreacted.io/rss.xml"); | ||
this.addURLButton = page.getByRole("button", { name: "Add" }); | ||
this.deleteURLButton = page.getByRole("button", { name: "X" }); | ||
this.loginFormTitle = page.getByRole("heading", { name: "Log In Form" }); | ||
this.loginUsernameField = page.getByPlaceholder("Username"); | ||
this.loginPasswordField = page.getByPlaceholder("******"); | ||
this.saveURLsButton = page.getByRole("button", { name: "Save Urls" }); | ||
this.logoutButton = page.getByText("Log Out"); | ||
this.subscribeModalButton = page.getByText("Subscribe").first(); | ||
this.subscribeFormButton = page.getByText("Subscribe").nth(2); | ||
this.subscribeEmailField = page.getByPlaceholder("[email protected]"); | ||
this.unsubscribeButton = page.getByRole("button", { name: "Unsubscribe" }); | ||
this.loginModalButton = page | ||
.locator("div") | ||
.filter({ hasText: /^Log In$/ }) | ||
.locator("label"); | ||
this.loginFormButton = page | ||
.locator("form") | ||
.getByText("Log In", { exact: true }); | ||
this.skeletonLoading = page.locator(".skeleton"); | ||
} | ||
|
||
async goto(urls?: string[]): Promise<void> { | ||
if (urls !== undefined) { | ||
await this.assertRSSList({ | ||
expectedPostData: [urls], | ||
trigger: async () => { | ||
await this.page.goto(`${this.pageURL}/?url=${urls.join(",")}`); | ||
}, | ||
}); | ||
return; | ||
} | ||
|
||
await this.page.goto(this.pageURL); | ||
} | ||
|
||
async expectHaveURLParam(urls: string[]) { | ||
await expect(this.page).toHaveURL(`${this.pageURL}/?url=${urls.join(",")}`); | ||
} | ||
|
||
async expectNotHaveURLParam() { | ||
await expect(this.page).toHaveURL(this.pageURL); | ||
} | ||
|
||
async waitLoadingPage() { | ||
const firstSkeletonLoading = this.skeletonLoading.first(); | ||
await firstSkeletonLoading.waitFor({ state: "visible" }); | ||
await firstSkeletonLoading.waitFor({ state: "detached" }); | ||
} | ||
|
||
async addURL(url: string) { | ||
await this.urlInput.fill(url); | ||
|
||
await this.assertRSSList({ | ||
expectedPostData: [[url]], | ||
trigger: async () => { | ||
await this.addURLButton.click(); | ||
}, | ||
}); | ||
|
||
await expect(this.urlInput).toHaveValue(""); | ||
} | ||
|
||
async deleteURL(nth?: number) { | ||
if (nth !== undefined) { | ||
await this.deleteURLButton.nth(nth - 1).click(); | ||
return; | ||
} | ||
await this.deleteURLButton.first().click(); | ||
} | ||
|
||
async saveURLs(expectedURLs: string[]) { | ||
await this.assertSaveRSSUrls({ | ||
expectedPostData: [[this.loginResonse?.["UserId"], expectedURLs]], | ||
trigger: async () => { | ||
await this.saveURLsButton.click(); | ||
}, | ||
}); | ||
} | ||
|
||
async subscribe(email: string) { | ||
await this.subscribeModalButton.click(); | ||
await this.subscribeEmailField.fill(email); | ||
|
||
await this.assertSubscribe({ | ||
expectedPostData: [[this.loginResonse?.["UserId"], email]], | ||
trigger: async () => { | ||
await this.subscribeFormButton.click(); | ||
}, | ||
}); | ||
} | ||
|
||
async unsubscribe(email: string) { | ||
await this.assertUnsubscribe({ | ||
expectedPostData: [email], | ||
trigger: async () => { | ||
await this.unsubscribeButton.click(); | ||
}, | ||
}); | ||
} | ||
|
||
async login(username: string, password: string) { | ||
await this.loginModalButton.click(); | ||
await expect(this.loginFormTitle).toBeVisible(); | ||
|
||
await this.loginUsernameField.fill(username); | ||
await this.loginPasswordField.fill(password); | ||
|
||
const loginResponse = await this.assertLoginOrRegister({ | ||
expectedPostData: [{ Username: username, Password: password }], | ||
trigger: async () => { | ||
await this.loginFormButton.click(); | ||
}, | ||
}); | ||
await this.assertLocalStorageExist(this.sessionKey); | ||
|
||
this.loginResonse = loginResponse["Success"]; | ||
} | ||
|
||
async logout() { | ||
await this.logoutButton.click(); | ||
await this.assertLocalStorageNotExist(this.sessionKey); | ||
|
||
this.loginResonse = undefined; | ||
} | ||
|
||
async assertRSSList(option: { | ||
trigger: () => Promise<void>; | ||
expectedPostData: unknown; | ||
}) { | ||
return await this.assertAPICall({ | ||
...option, | ||
url: "**/rpc/IRPCStore/getRSSList", | ||
}); | ||
} | ||
|
||
async assertSaveRSSUrls(option: { | ||
trigger: () => Promise<void>; | ||
expectedPostData: unknown; | ||
}) { | ||
return await this.assertAPICall({ | ||
...option, | ||
url: "**/rpc/IRPCStore/saveRSSUrls", | ||
}); | ||
} | ||
|
||
async assertSubscribe(option: { | ||
trigger: () => Promise<void>; | ||
expectedPostData: unknown; | ||
}) { | ||
return await this.assertAPICall({ | ||
...option, | ||
url: "**/rpc/IRPCStore/subscribe", | ||
}); | ||
} | ||
|
||
async assertUnsubscribe(option: { | ||
trigger: () => Promise<void>; | ||
expectedPostData: unknown; | ||
}) { | ||
return await this.assertAPICall({ | ||
...option, | ||
url: "**/rpc/IRPCStore/unsubscribe", | ||
}); | ||
} | ||
|
||
async assertLoginOrRegister(option: { | ||
trigger: () => Promise<void>; | ||
expectedPostData: unknown; | ||
}) { | ||
return await this.assertAPICall({ | ||
...option, | ||
url: "**/rpc/IRPCStore/loginOrRegister", | ||
}); | ||
} | ||
|
||
async assertAPICall(option: { | ||
url: string; | ||
|
||
trigger: () => Promise<void>; | ||
expectedPostData: unknown; | ||
}) { | ||
const { url, trigger, expectedPostData } = option; | ||
|
||
const responsePromise = this.page.waitForResponse(url); | ||
|
||
await trigger(); | ||
|
||
const response = await responsePromise; | ||
expect(response.ok()).toStrictEqual(true); | ||
expect(response.request().postDataJSON()).toStrictEqual(expectedPostData); | ||
|
||
return response.json(); | ||
} | ||
|
||
async assertLocalStorageExist(key: string) { | ||
await this.page.waitForFunction((key) => { | ||
return localStorage[key] !== undefined; | ||
}, key); | ||
} | ||
|
||
async assertLocalStorageNotExist(key: string) { | ||
await this.page.waitForFunction((key) => { | ||
return localStorage[key] === undefined; | ||
}, key); | ||
} | ||
} |
Oops, something went wrong.