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

feat(agora): migrate Agora e2e tests (AG-1609) #2965

Open
wants to merge 7 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 6 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
15 changes: 14 additions & 1 deletion apps/agora/app/.eslintrc.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"extends": ["../../../.eslintrc.json"],
"extends": ["plugin:playwright/recommended", "../../../.eslintrc.json"],
"ignorePatterns": ["!**/*"],
"overrides": [
{
Expand Down Expand Up @@ -29,6 +29,19 @@
"files": ["*.html"],
"extends": ["plugin:@nx/angular-template"],
"rules": {}
},
{
"files": ["e2e/**/*.{ts,js,tsx,jsx}", "e2e/**/*.spec.{ts,js,tsx,jsx}"],
"plugins": ["@typescript-eslint"],
"parserOptions": {
"project": "./apps/agora/app/tsconfig.*?.json"
},
"rules": {
"@typescript-eslint/no-floating-promises": "error",
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Recommended by Playwright's best practices

"playwright/no-nested-step": "off",
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I often use nested steps to better organize complicated test, e.g. step to wait for GCT page to load, step to close GCT help dialog, step to change GCT dropdown, etc... it's helpful for identifying failures in long running tests with many actions. If we land on a different convention in the future, we can turn on this rule!

"playwright/no-conditional-in-test": "off",
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've found conditionals to be useful to handle temporary components, such as auto-closing toasts, where the environment can impact whether the component is still visible when the test reaches the step to dismiss it.

"playwright/expect-expect": "off"
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This rule enforces that every test has at least one expect call. Many of our tests use functions to encapsulate expectations rather than calling expect directly. We should be able to specify these functions in the rule configuration, but I was unable to get this working, so turning off for now.

}
}
]
}
341 changes: 341 additions & 0 deletions apps/agora/app/e2e/gene-comparison-tool-pinning-cache.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,341 @@
import { expect, test } from '@playwright/test';
import {
GCT_CATEGORIES,
GCT_PROTEIN_SUBCATEGORIES,
GCT_RNA_SUBCATEGORIES,
URL_GCT,
URL_GCT_PROTEIN_TMT,
} from './helpers/constants';
import { gene2WithMultipleProteinsTMT, geneWithMultipleProteinsTMT } from './helpers/data';
import { changeGctCategory, changeGctSubcategory, expectGctPageLoaded } from './helpers/gct';
import {
confirmPinnedItemsByGeneName,
confirmPinnedItemsByItemName,
confirmPinnedItemsCount,
confirmPinnedProteins,
expectPinnedGenesCountText,
expectPinnedProteinsCountText,
pinAllItemsViaSearchByGene,
pinGeneViaSearch,
pinMultipleGenesViaSearch,
} from './helpers/gct-pinning';

test.describe('GCT: Caching pinned genes', () => {
test('Pinned genes are maintained when switching between RNA subcategories', async ({ page }) => {
const genes = ['CYB561A3', 'MANBAL', 'PLEC', 'GFAP'];
const nGenes = genes.length;

await page.goto(URL_GCT);
await expectGctPageLoaded(page, GCT_CATEGORIES.RNA, GCT_RNA_SUBCATEGORIES.AD);

await pinMultipleGenesViaSearch(page, genes);

await test.step('confirm # genes pinned on AD subcategory page', async () => {
await expectPinnedGenesCountText(page, nGenes);
await confirmPinnedItemsCount(page, nGenes);
});

await changeGctSubcategory(
page,
GCT_CATEGORIES.RNA,
GCT_RNA_SUBCATEGORIES.AD,
GCT_RNA_SUBCATEGORIES.AD_AOD,
);

await changeGctSubcategory(
page,
GCT_CATEGORIES.RNA,
GCT_RNA_SUBCATEGORIES.AD_AOD,
GCT_RNA_SUBCATEGORIES.AD_SEX_F,
);

await changeGctSubcategory(
page,
GCT_CATEGORIES.RNA,
GCT_RNA_SUBCATEGORIES.AD_SEX_F,
GCT_RNA_SUBCATEGORIES.AD_SEX_M,
);

// back to original subcategory
await changeGctSubcategory(
page,
GCT_CATEGORIES.RNA,
GCT_RNA_SUBCATEGORIES.AD_SEX_M,
GCT_RNA_SUBCATEGORIES.AD,
);

await test.step('confirm same genes pinned on AD subcategory page', async () => {
await expectPinnedGenesCountText(page, nGenes);
await confirmPinnedItemsCount(page, nGenes);
await confirmPinnedItemsByItemName(page, genes);
});
});

test('Pinned genes are maintained when switching categories: RNA -> Protein -> RNA', async ({
page,
}) => {
const genes = ['CYB561A3', 'MANBAL', 'PLEC', 'GFAP'];
const nGenes = genes.length;

await page.goto(URL_GCT);
await expectGctPageLoaded(page, GCT_CATEGORIES.RNA, GCT_RNA_SUBCATEGORIES.AD);

await pinMultipleGenesViaSearch(page, genes);

await test.step('confirm # genes pinned on RNA page', async () => {
await expectPinnedGenesCountText(page, nGenes);
await confirmPinnedItemsCount(page, nGenes);
});

await changeGctCategory(page, GCT_CATEGORIES.RNA, GCT_CATEGORIES.PROTEIN);

await changeGctSubcategory(
page,
GCT_CATEGORIES.PROTEIN,
GCT_PROTEIN_SUBCATEGORIES.SRM,
GCT_PROTEIN_SUBCATEGORIES.TMT,
);

await changeGctSubcategory(
page,
GCT_CATEGORIES.PROTEIN,
GCT_PROTEIN_SUBCATEGORIES.TMT,
GCT_PROTEIN_SUBCATEGORIES.LFQ,
);

// back to original category
await changeGctCategory(page, GCT_CATEGORIES.PROTEIN, GCT_CATEGORIES.RNA);

await test.step('confirm same genes pinned on RNA page', async () => {
await expectPinnedGenesCountText(page, nGenes);
await confirmPinnedItemsCount(page, nGenes);
await confirmPinnedItemsByItemName(page, genes);
});
});

test('Pinned proteins are maintained when switching between Protein subcategories', async ({
page,
}) => {
const gene1 = geneWithMultipleProteinsTMT.name;
const gene2 = gene2WithMultipleProteinsTMT.name;
const genes = [gene1, gene2];
const nGenes = genes.length;

const proteins1 = geneWithMultipleProteinsTMT.uniProtIds;
const proteins2 = gene2WithMultipleProteinsTMT.uniProtIds;
const nProteins = proteins1.length + proteins2.length;

await page.goto(URL_GCT_PROTEIN_TMT);
await expectGctPageLoaded(page, GCT_CATEGORIES.PROTEIN, GCT_PROTEIN_SUBCATEGORIES.TMT);

for (const gene of genes) {
await pinAllItemsViaSearchByGene(page, gene);
}

await test.step('confirm # genes and proteins pinned on Protein page', async () => {
await expectPinnedGenesCountText(page, nGenes);
await expectPinnedProteinsCountText(page, nProteins);
await confirmPinnedItemsCount(page, nProteins);
});

await changeGctSubcategory(
page,
GCT_CATEGORIES.PROTEIN,
GCT_PROTEIN_SUBCATEGORIES.TMT,
GCT_PROTEIN_SUBCATEGORIES.SRM,
);

await changeGctSubcategory(
page,
GCT_CATEGORIES.PROTEIN,
GCT_PROTEIN_SUBCATEGORIES.SRM,
GCT_PROTEIN_SUBCATEGORIES.LFQ,
);

// back to original subcategory
await changeGctSubcategory(
page,
GCT_CATEGORIES.PROTEIN,
GCT_PROTEIN_SUBCATEGORIES.LFQ,
GCT_PROTEIN_SUBCATEGORIES.TMT,
);

await test.step('confirm same genes and proteins pinned on Protein page', async () => {
await expectPinnedGenesCountText(page, nGenes);
await expectPinnedProteinsCountText(page, nProteins);
await confirmPinnedItemsCount(page, nProteins);

await confirmPinnedProteins(page, gene1, proteins1);
await confirmPinnedProteins(page, gene2, proteins2);
});
});

test('Pinned proteins are maintained when switching categories: Protein -> RNA -> Protein', async ({
page,
}) => {
const gene1 = geneWithMultipleProteinsTMT.name;
const gene2 = gene2WithMultipleProteinsTMT.name;
const genes = [gene1, gene2];
const nGenes = genes.length;

const proteins1 = geneWithMultipleProteinsTMT.uniProtIds;
const proteins2 = gene2WithMultipleProteinsTMT.uniProtIds;
const nProteins = proteins1.length + proteins2.length;

await page.goto(URL_GCT_PROTEIN_TMT);
await expectGctPageLoaded(page, GCT_CATEGORIES.PROTEIN, GCT_PROTEIN_SUBCATEGORIES.TMT);

for (const gene of genes) {
await pinAllItemsViaSearchByGene(page, gene);
}

await test.step('confirm # genes and proteins pinned on Protein page', async () => {
await expectPinnedGenesCountText(page, nGenes);
await expectPinnedProteinsCountText(page, nProteins);
await confirmPinnedItemsCount(page, nProteins);
});

await changeGctCategory(page, GCT_CATEGORIES.PROTEIN, GCT_CATEGORIES.RNA);

await changeGctSubcategory(
page,
GCT_CATEGORIES.RNA,
GCT_RNA_SUBCATEGORIES.AD,
GCT_RNA_SUBCATEGORIES.AD_AOD,
);

// back to original category
await changeGctCategory(page, GCT_CATEGORIES.RNA, GCT_CATEGORIES.PROTEIN);

// back to original subcategory
await changeGctSubcategory(
page,
GCT_CATEGORIES.PROTEIN,
GCT_PROTEIN_SUBCATEGORIES.SRM,
GCT_PROTEIN_SUBCATEGORIES.TMT,
);

await test.step('confirm same genes and proteins pinned on Protein page', async () => {
await expectPinnedGenesCountText(page, nGenes);
await expectPinnedProteinsCountText(page, nProteins);

await confirmPinnedItemsCount(page, nProteins);
await confirmPinnedProteins(page, gene1, proteins1);
await confirmPinnedProteins(page, gene2, proteins2);
});
});

test('Last pinned genes are maintained even if proteins were pinned initially', async ({
page,
}) => {
const rnaCategoryGene = geneWithMultipleProteinsTMT.name;
const rnaCategoryProteins = geneWithMultipleProteinsTMT.uniProtIds;
const proteinCategoryGene = gene2WithMultipleProteinsTMT.name;

await test.step('pin proteins in Protein category', async () => {
await page.goto(URL_GCT_PROTEIN_TMT);
await expectGctPageLoaded(page, GCT_CATEGORIES.PROTEIN, GCT_PROTEIN_SUBCATEGORIES.TMT);

await pinAllItemsViaSearchByGene(page, proteinCategoryGene);
});

await test.step('pin genes in RNA category', async () => {
await changeGctCategory(page, GCT_CATEGORIES.PROTEIN, GCT_CATEGORIES.RNA);

await test.step('clear all items', async () => {
await page.getByRole('button', { name: 'Clear All' }).click();
await expect(page.getByText(/Pinned Genes/i)).toBeHidden();
});

await pinGeneViaSearch(page, rnaCategoryGene);

await test.step('confirm pinned gene', async () => {
await expectPinnedGenesCountText(page, 1);
await confirmPinnedItemsByGeneName(page, rnaCategoryGene, 1);
});
});

await test.step('Protein category pins have changed', async () => {
await changeGctCategory(page, GCT_CATEGORIES.RNA, GCT_CATEGORIES.PROTEIN);
await changeGctSubcategory(
page,
GCT_CATEGORIES.PROTEIN,
GCT_PROTEIN_SUBCATEGORIES.SRM,
GCT_PROTEIN_SUBCATEGORIES.TMT,
);
await expectPinnedGenesCountText(page, 1);
await expectPinnedProteinsCountText(page, rnaCategoryProteins.length);
await confirmPinnedProteins(page, rnaCategoryGene, rnaCategoryProteins);
});

await test.step('RNA category pins are maintained', async () => {
await changeGctCategory(page, GCT_CATEGORIES.PROTEIN, GCT_CATEGORIES.RNA);

await test.step('confirm pinned gene', async () => {
await expectPinnedGenesCountText(page, 1);
await confirmPinnedItemsByGeneName(page, rnaCategoryGene, 1);
});
});
});

test('Last pinned proteins are maintained even if genes were pinned initially', async ({
page,
}) => {
const rnaCategoryGene = geneWithMultipleProteinsTMT.name;
const proteinCategoryGene = gene2WithMultipleProteinsTMT.name;
const proteinCategoryProteins = gene2WithMultipleProteinsTMT.uniProtIds;

await test.step('pin genes in RNA category', async () => {
await page.goto(URL_GCT);
await expectGctPageLoaded(page, GCT_CATEGORIES.RNA, GCT_RNA_SUBCATEGORIES.AD);

await pinGeneViaSearch(page, rnaCategoryGene);
await confirmPinnedItemsByGeneName(page, rnaCategoryGene, 1);
});

await test.step('pin proteins in Protein category', async () => {
await changeGctCategory(page, GCT_CATEGORIES.RNA, GCT_CATEGORIES.PROTEIN);
await changeGctSubcategory(
page,
GCT_CATEGORIES.PROTEIN,
GCT_PROTEIN_SUBCATEGORIES.SRM,
GCT_PROTEIN_SUBCATEGORIES.TMT,
);

await test.step('clear all items', async () => {
await page.getByRole('button', { name: 'Clear All' }).click();
await expect(page.getByText(/Pinned Genes/i)).toBeHidden();
});

await pinAllItemsViaSearchByGene(page, proteinCategoryGene);

await test.step('confirm pinned items', async () => {
await expectPinnedGenesCountText(page, 1);
await expectPinnedProteinsCountText(page, proteinCategoryProteins.length);
await confirmPinnedProteins(page, proteinCategoryGene, proteinCategoryProteins);
});
});

await test.step('RNA category pins have changed', async () => {
await changeGctCategory(page, GCT_CATEGORIES.PROTEIN, GCT_CATEGORIES.RNA);
await expectPinnedGenesCountText(page, 1);
await confirmPinnedItemsByGeneName(page, proteinCategoryGene, 1);
});

await test.step('Protein category pins are maintained', async () => {
await changeGctCategory(page, GCT_CATEGORIES.RNA, GCT_CATEGORIES.PROTEIN);
await changeGctSubcategory(
page,
GCT_CATEGORIES.PROTEIN,
GCT_PROTEIN_SUBCATEGORIES.SRM,
GCT_PROTEIN_SUBCATEGORIES.TMT,
);

await test.step('confirm pinned items', async () => {
await expectPinnedGenesCountText(page, 1);
await expectPinnedProteinsCountText(page, proteinCategoryProteins.length);
await confirmPinnedProteins(page, proteinCategoryGene, proteinCategoryProteins);
});
});
});
});
Loading
Loading