Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Chore/fx e2e test updates #2368

Open
wants to merge 17 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
4 changes: 2 additions & 2 deletions packages/client/e2e/credit.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,9 @@ test.describe("Credit", () => {
if (!triggerSellSide) {
// if we want to avoid popping up the sell side window (should be minority of tests)
// select all, then the click on Adaptive Bank below will switch off the sell side for that test
await newRfqPage.page.getByLabel(/All/).click()
await newRfqPage.selectAllCounterparties()
}
await newRfqPage.adaptiveBankToggle.click()
await newRfqPage.selectAdaptiveBankCounterparty()

const pagePromise = triggerSellSide
? browserContext.waitForEvent("page", {
Expand Down
114 changes: 64 additions & 50 deletions packages/client/e2e/fixtures.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,55 +5,55 @@ import {
CreditBlotterPageObject,
CreditNewRfqPageObject,
CreditRfqTilesPageObject,
FxAnalyticsPageObject,
FxBlotterPageObject,
FxTilesPageObject,
LimitCheckerPageObject,
} from "./pages"
import { isOpenFin } from "./utils"

dotenv.config({ path: ".env.development" })
dotenv.config()

type FXPage = "mainWindow" | "fx-tiles" | "fx-blotter" | "fx-analytics"

const RUNTIME_ADDRESS = process.env.OPENFIN_RUNTIME_ADDRESS ?? ""

type FxPages = {
mainPage: Page
tilePO: FxTilesPageObject
blotterPO: FxBlotterPageObject
analyticsPO: FxAnalyticsPageObject
}

type CreditPages = {
blotterPO: CreditBlotterPageObject
newRfqPO: CreditNewRfqPageObject
rfqsPO: CreditRfqTilesPageObject
}

interface Fixtures {
fxPages: Record<FXPage, Page>
fxPages: FxPages
creditPages: CreditPages
limitCheckerPage: Page
limitCheckerPO: LimitCheckerPageObject
}

const fxOpenfinUrlPaths: string[] = [
"openfin-window-frame?app=FX",
"fx-tiles",
"fx-blotter",
"fx-analytics",
]

const creditOpenfinUrlSuffixes: Record<string, keyof CreditPages> = {
"credit-blotter": "blotterPO",
"credit-new-rfq": "newRfqPO",
"credit-rfqs": "rfqsPO",
}

const limitCheckerUrlPath = "limit-checker"

const urlPathToFxPage = (path: string): FXPage => {
switch (path) {
case "openfin-window-frame?app=FX":
return "mainWindow"
default:
return path as FXPage
}
const fxOpenFinUrlSuffixes: Record<string, keyof FxPages> = {
"openfin-window-frame?app=FX": "mainPage",
"fx-blotter": "blotterPO",
"fx-tiles": "tilePO",
"fx-analytics": "analyticsPO",
}

const limitCheckerUrlPath = "limit-checker"

export const test = base.extend<Fixtures>({
browser: async ({}, use, workerInfo) => {
if (isOpenFin(workerInfo)) {
browser: async ({}, use, testInfo) => {
if (isOpenFin(testInfo)) {
const runtimeConnection = await chromium.connectOverCDP(RUNTIME_ADDRESS)
await use(runtimeConnection)
} else {
Expand All @@ -75,36 +75,54 @@ export const test = base.extend<Fixtures>({
use(context)
}
},
fxPages: async ({ context }, use, workerInfo) => {
fxPages: async ({ context }, use, testInfo) => {
const contextPages = context.pages()

if (isOpenFin(workerInfo)) {
const pages = fxOpenfinUrlPaths.reduce(
(rec, urlPath) => {
if (isOpenFin(testInfo)) {
use(
Object.keys(fxOpenFinUrlSuffixes).reduce<FxPages>((rec, urlPath) => {
const page = contextPages.find(
(p) => p.url() === `${process.env.E2E_RTC_WEB_ROOT_URL}/${urlPath}`,
)

if (!page) throw Error(`Openfin page at ${urlPath} was not found`)
return { ...rec, [urlPathToFxPage(urlPath)]: page }
},
{} as Record<FXPage, Page>,

switch (urlPath) {
case "openfin-window-frame?app=FX":
rec.mainPage = page
break
case "fx-blotter":
rec.blotterPO = new FxBlotterPageObject(page, testInfo)
break
case "fx-tiles":
page.setViewportSize({ height: 1280, width: 1024 })
rec.tilePO = new FxTilesPageObject(page, testInfo)
break
case "fx-analytics":
rec.analyticsPO = new FxAnalyticsPageObject(page, testInfo)
break
default:
throw Error(`Unknown Openfin page URL - ${urlPath}`)
}
return rec
}, {} as FxPages),
)
use(pages)
} else {
const mainWindow =
const mainPage =
contextPages.length > 0 ? contextPages[0] : await context.newPage()
await mainPage.goto(`${process.env.E2E_RTC_WEB_ROOT_URL}`)
use({
mainWindow,
"fx-analytics": mainWindow,
"fx-blotter": mainWindow,
"fx-tiles": mainWindow,
mainPage,
tilePO: new FxTilesPageObject(mainPage, testInfo),
blotterPO: new FxBlotterPageObject(mainPage, testInfo),
analyticsPO: new FxAnalyticsPageObject(mainPage, testInfo),
})
}
},
creditPages: async ({ context }, use, workerInfo) => {
creditPages: async ({ context }, use, testInfo) => {
const contextPages = context.pages()

if (isOpenFin(workerInfo)) {
if (isOpenFin(testInfo)) {
use(
Object.keys(creditOpenfinUrlSuffixes).reduce<CreditPages>(
(rec, urlPath) => {
Expand All @@ -117,14 +135,14 @@ export const test = base.extend<Fixtures>({

switch (urlPath) {
case "credit-blotter":
rec.blotterPO = new CreditBlotterPageObject(page, workerInfo)
rec.blotterPO = new CreditBlotterPageObject(page, testInfo)
break
case "credit-new-rfq":
rec.newRfqPO = new CreditNewRfqPageObject(page, workerInfo)
rec.newRfqPO = new CreditNewRfqPageObject(page, testInfo)
break
case "credit-rfqs":
page.setViewportSize({ width: 1280, height: 1024 })
rec.rfqsPO = new CreditRfqTilesPageObject(page, workerInfo)
rec.rfqsPO = new CreditRfqTilesPageObject(page, testInfo)
break
default:
throw Error(`Unknown Openfin page URL - ${urlPath}`)
Expand All @@ -139,29 +157,25 @@ export const test = base.extend<Fixtures>({
contextPages.length > 0 ? contextPages[0] : await context.newPage()
await mainPage.goto(`${process.env.E2E_RTC_WEB_ROOT_URL}/credit`)
use({
blotterPO: new CreditBlotterPageObject(mainPage, workerInfo),
newRfqPO: new CreditNewRfqPageObject(mainPage, workerInfo),
rfqsPO: new CreditRfqTilesPageObject(mainPage, workerInfo),
blotterPO: new CreditBlotterPageObject(mainPage, testInfo),
newRfqPO: new CreditNewRfqPageObject(mainPage, testInfo),
rfqsPO: new CreditRfqTilesPageObject(mainPage, testInfo),
})
}
},
limitCheckerPage: async ({ context }, use, workerInfo) => {
limitCheckerPO: async ({ context }, use, testInfo) => {
const contextPages = context.pages()

if (isOpenFin(workerInfo)) {
if (isOpenFin(testInfo)) {
const page = contextPages.find(
(p) =>
p.url() ===
`${process.env.E2E_RTC_WEB_ROOT_URL}/${limitCheckerUrlPath}`,
)
if (!page)
throw Error(`Openfin page at ${limitCheckerUrlPath} was not found`)
use(page)
} else {
const mainPage =
contextPages.length > 0 ? contextPages[0] : await context.newPage()

use(mainPage)
use(new LimitCheckerPageObject(page, testInfo))
}
},
})
126 changes: 53 additions & 73 deletions packages/client/e2e/fx-analytics.spec.ts
Original file line number Diff line number Diff line change
@@ -1,58 +1,32 @@
import { expect, Page } from "@playwright/test"
import { expect } from "@playwright/test"

import { test } from "./fixtures"
import { ExpectTimeout, isOpenFin } from "./utils"

const currencyPairs = [
"EUR/USD",
"USD/JPY",
"GBP/USD",
"GBP/JPY",
"EUR/JPY",
"AUD/USD",
"NZD/USD",
"EUR/CAD",
]

const currencies = ["NZD", "USD", "JPY", "GBP", "EUR", "CAD", "AUD"]

test.describe("Analytics panel", () => {
let analyticsPage: Page

test.beforeAll(async ({ context, fxPages }, workerInfo) => {
if (isOpenFin(workerInfo)) {
analyticsPage = fxPages["fx-analytics"]
} else {
const pages = context.pages()
const mainWindow = pages.length > 0 ? pages[0] : await context.newPage()

await mainWindow.goto(`${process.env.E2E_RTC_WEB_ROOT_URL}`)

analyticsPage = mainWindow
}
})
import { ExpectTimeout } from "./utils"

test.describe("FX Analytics", () => {
test.describe("Profit & Loss section", () => {
test("Last Profit & Loss amount is displayed in numerical format @smoke", async () => {
const lastPnlAmount = await analyticsPage
.locator("[data-testid='lastPosition']")
.textContent()

const regexp = RegExp(`[-+,.0-9]`, "g")
expect(lastPnlAmount).toMatch(regexp)
test("Last Profit & Loss amount is displayed in numerical format @smoke", async ({
fxPages: { analyticsPO },
}) => {
const lastPnlAmount = await analyticsPO.lastPnLPosition.textContent()
expect(lastPnlAmount).toMatch(/[-+,.0-9]/)
})

test("Profit & Loss amount is updated periodically", async () => {
const pnlLocator = analyticsPage.locator("[data-testid='lastPosition']")
test("Profit & Loss amount is updated periodically", async ({
fxPages: { analyticsPO },
}) => {
const pnlLocator = analyticsPO.lastPnLPosition
const initialPnlAmount = await pnlLocator.textContent()

await expect(pnlLocator).not.toContainText(initialPnlAmount ?? "", {
timeout: ExpectTimeout.MEDIUM,
})
})

test("Correct text color is displayed based on Profit & Loss amount", async () => {
const pnlLocator = analyticsPage.locator("[data-testid='lastPosition']")
test("Correct text color is displayed based on Profit & Loss amount", async ({
fxPages: { analyticsPO },
}) => {
const pnlLocator = analyticsPO.lastPnLPosition

const pnlText = await pnlLocator.textContent()

Expand All @@ -68,37 +42,31 @@ test.describe("Analytics panel", () => {
)
})
})

test.describe("Positions section", () => {
test("Position nodes are showing tooltip information for each currencies", async () => {
for (const currency of currencies) {
const currencyCircle = analyticsPage
.locator("g.node")
.filter({ hasText: currency })
.first()
const currencyTooltip = analyticsPage
.locator("[data-testid='tooltip']", { hasText: currency })
.first()

await currencyCircle.hover()
const currencies = ["NZD", "USD", "JPY", "GBP", "EUR", "CAD", "AUD"]

currencies.forEach((currency) => {
test(`Position nodes are showing tooltip information for ${currency}`, async ({
fxPages: { analyticsPO },
}) => {
await analyticsPO.bubble(currency).hover()

const currencyTooltip = analyticsPO.bubbleTooltip(currency)
await expect(currencyTooltip).toBeVisible()
const regexp = RegExp(`${currency} [-+,.0-9]`, "g")

expect(
await currencyTooltip.textContent(),
`tooltip for ${currency} doesn't match expected pattern`,
).toMatch(regexp)
}
).toMatch(RegExp(`${currency} [-+,.0-9]`))
})
})

test("Position nodes can be moved", async () => {
const nzdNode = analyticsPage
.locator("g.node")
.filter({ hasText: "NZD" })
.first()

const jpyNode = analyticsPage
.locator("g.node")
.filter({ hasText: "JPY" })
.first()
test("Position nodes can be moved", async ({
fxPages: { analyticsPO },
}) => {
const nzdNode = analyticsPO.bubble("NZD")
const jpyNode = analyticsPO.bubble("JPY")

const nzdInitialPosition = await nzdNode.boundingBox()
await nzdNode.dragTo(jpyNode)
Expand All @@ -107,20 +75,32 @@ test.describe("Analytics panel", () => {
})

test.describe("PnL section", () => {
test("PnL value is displayed for each currencies", async () => {
for (const currencypair of currencyPairs) {
const amountString = await analyticsPage
.getByTestId(`pnlbar-${currencypair}`)
.getByTestId("priceLabel")
const currencyPairs = [
"EUR/USD",
"USD/JPY",
"GBP/USD",
"GBP/JPY",
"EUR/JPY",
"AUD/USD",
"NZD/USD",
"EUR/CAD",
]

currencyPairs.forEach((currencyPair) => {
test(`PnL value is displayed for ${currencyPair}`, async ({
fxPages: { analyticsPO },
}) => {
const amountString = await analyticsPO
.pnlAmount(currencyPair)
.textContent()

const regexp = RegExp(`[-,.0-9km]`, "g")

expect(
amountString,
`amount for ${currencypair} doesn't match abbreviated numerical pattern`,
`amount for ${currencyPair} doesn't match abbreviated numerical pattern`,
).toMatch(regexp)
}
})
})
})
})
Loading