Skip to content
Merged
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
10 changes: 9 additions & 1 deletion packages/locuszoom/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,12 @@ node_modules
npm-debug.log*
pnpm-debug.log*
yarn-debug.log*
yarn-error.log*
yarn-error.log*

# Playwright
/test-results/
/playwright-report/
/blob-report/
/playwright/.cache/
/playwright/.auth/
/.github/
27 changes: 27 additions & 0 deletions packages/locuszoom/e2e/example.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// @ts-check
import { test, expect } from '@playwright/test';

test('Run plot', async ({ page }) => {

// Test variables

const URL = 'http://localhost:5173/';
const CHR_INPUT = 'raya560ne.2.1.2'; // a chromosome
const POINT = '#lz-plot_association_associationpvalues_-RAYA560NE21261284_TC' // a point in the plot
const POINT_LOCATOR = page.locator(POINT);
const PHENO_STAT = '×phenRAYA560NE.2.1.2:61284_T/'; // stats' table for the point
const PHENO_STAT_TO_CLICK = page.getByText(PHENO_STAT)

// Test execution

await page.goto(URL);
await page.getByRole('button').click();
await page.getByRole('textbox', { name: 'Please Input' }).nth(1).fill(CHR_INPUT);
await expect(POINT_LOCATOR).toBeVisible();
await POINT_LOCATOR.click();
await PHENO_STAT_TO_CLICK.click();
await expect(PHENO_STAT_TO_CLICK).toBeVisible();
await page.getByRole('button', { name: '×' }).click();
await expect(PHENO_STAT_TO_CLICK).toBeHidden();
});

69 changes: 36 additions & 33 deletions packages/locuszoom/package.json
Original file line number Diff line number Diff line change
@@ -1,35 +1,38 @@
{
"name": "@galaxyproject/locuszoom",
"version": "0.0.7",
"type": "module",
"license": "MIT",
"files": [
"static"
],
"scripts": {
"dev": "vite",
"build": "vite build",
"preview": "vite preview",
"prettier": "prettier --config ./prettier.config.js --write 'package.json' '**/*.{js,jsx,ts,tsx,json,css,md,vue}'",
"test": "vitest --run",
"test:watch": "vitest --watch",
"test:ui": "vitest --ui"
},
"devDependencies": {
"@types/node": "^22.9.0",
"@vitejs/plugin-vue": "^5.0.5",
"@vitest/ui": "^3.0.9",
"autoprefixer": "^10.4.19",
"galaxy-charts": "^0.0.73",
"galaxy-charts-xml-parser": "^1.0.3",
"jsdom": "^25.0.1",
"locuszoom": "^0.14.0",
"postcss": "^8.4.40",
"prettier": "^3.3.3",
"tailwindcss": "^3.4.7",
"typescript": "^5.5.4",
"vite": "^6.2.2",
"vitest": "^3.0.9",
"vue": "^3.4.31"
}
"name": "@galaxyproject/locuszoom",
"version": "0.0.8",
"type": "module",
"license": "MIT",
"files": [
"static"
],
"scripts": {
"dev": "vite",
"build": "vite build",
"preview": "vite preview",
"prettier": "prettier --config ./prettier.config.js --write 'package.json' '**/*.{js,jsx,ts,tsx,json,css,md,vue}'",
"test": "npm run test:unit && npm run test:e2e",
"test:e2e": "npx playwright test",
"test:unit": "vitest run",
"test:watch": "vitest --watch",
"test:ui": "vitest --ui"
},
"devDependencies": {
"@playwright/test": "^1.58.0",
"@types/node": "^22.9.0",
"@vitejs/plugin-vue": "^5.0.5",
"@vitest/ui": "^3.0.9",
"autoprefixer": "^10.4.19",
"galaxy-charts": "^0.0.73",
"galaxy-charts-xml-parser": "^1.0.3",
"jsdom": "^25.0.1",
"locuszoom": "^0.14.0",
"postcss": "^8.4.40",
"prettier": "^3.3.3",
"tailwindcss": "^3.4.7",
"typescript": "^5.5.4",
"vite": "^6.2.2",
"vitest": "^3.0.9",
"vue": "^3.4.31"
}
}
10 changes: 10 additions & 0 deletions packages/locuszoom/playwright.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { defineConfig } from "@playwright/test";

export default defineConfig({
testIgnore: ["src/**"],
timeout: 120000, // 120 seconds per test
use: {
headless: !!process.env.CI,
},
snapshotPathTemplate: "{testDir}/test-data/{arg}.png",
});
8 changes: 3 additions & 5 deletions packages/locuszoom/public/locuszoom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,7 @@
<input>
<label>Select a chromosome</label>
<name>chromosome</name>
<type>integer</type>
<min>1</min>
<value>1</value>
<type>string</type>
</input>
<input>
<label>Select start position</label>
Expand Down Expand Up @@ -97,7 +95,7 @@
<param name="dataset_id" value="http://cdn.jsdelivr.net/gh/galaxyproject/galaxy-test-data/1.gwas_tabix.gz" ftype="gwas_tabix.gz" />
</test>
</tests>
<help format="markdown"><![CDATA[
<help format="markdown"><![CDATA[
# What is LocusZoom?

LocusZoom is a specialized tool designed to create interactive Manhattan plots for visualizing results from genome-wide association studies (GWAS).
Expand All @@ -117,5 +115,5 @@ For more information:

Boughton, A. P. et al. LocusZoom.js: interactive and embeddable visualization of genetic association study results. Bioinformatics (2021) doi:10.1093/bioinformatics/btab186.

]]></help>
]]> </help>
</visualization>
35 changes: 32 additions & 3 deletions packages/locuszoom/src/Plugin.vue
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,11 @@ LocusZoom.use(LzTabixSource);

const TabixUrlSource = LocusZoom.Adapters.get("TabixUrlSource");

// Test files paths

const BGZIP_PRIMARY_DATASET_PATH = "http://localhost:5173/test-data/weird.gwas_bgzip";
const TABIX_SECONDARY_DATASET_PATH = "http://localhost:5173/test-data/weird.gwas_bgzip.tbi";

// Patch URLFetchable prototype by accessing it through a reader instance
let hasURLFetchablePrototypeBeenPatched = false;

Expand Down Expand Up @@ -160,7 +165,31 @@ const props = defineProps({

const errorMessage = ref("");

// Functions to retrieve URLs

function getPrimaryURL(root,primaryID) {
if (primaryID==="__test__"){
return BGZIP_PRIMARY_DATASET_PATH;
}
else {
return `${root}api/datasets/${primaryID}/display`;
}

}

function getSecondaryURL(root,primaryID, secondaryID) {
if (primaryID==="__test__"){
return TABIX_SECONDARY_DATASET_PATH;
}
else {
return `${root}api/datasets/${secondaryID}/display`;
}

}

function render() {
const bgzipURL = getPrimaryURL(props.root,props.datasetId);
const tabixURL = getSecondaryURL(props.root,props.datasetId, props.settings.tabix?.id);
const id = props.settings.tabix?.id;
const chrIn = props.settings.chromosome;
const startIn = props.settings.start;
Expand All @@ -173,7 +202,7 @@ function render() {
const is_neg_log_pvalue = props.settings.is_neg_log_pvalue;
const beta_col = props.settings.beta_col;
const stderr_beta_col = props.settings.stderr_beta_col;
if (!id) {
if (tabixURL.includes("/api/datasets/undefined/display")) {
errorMessage.value = "Please select a Tabix file.";
return;
}
Expand All @@ -199,8 +228,8 @@ function render() {
let data_sources = new LocusZoom.DataSources().add("assoc", [
"TabixUrlSource",
{
url_data: `${props.root}api/datasets/${props.datasetId}/display`,
url_tbi: `${props.root}api/datasets/${id}/display`,
url_data: bgzipURL,
url_tbi: tabixURL,
parser_func: gwasParser,
overfetch: 0,
},
Expand Down
4 changes: 2 additions & 2 deletions packages/locuszoom/src/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,10 @@ async function main() {
// Construct the incoming data object with mock configuration and data
const dataIncoming = {
visualization_config: {
dataset_id: "b620c45fba703209", // id of primary_dataset.bgzip
dataset_id: process.env.dataset_id || "__test__", // id of primary_dataset.bgzip
// Placeholder for additional visualization settings
settings: {
tabix: { id: "abd164196b68b912" }, // id of secondary_dataset.tbi
tabix: {}, // id of secondary_dataset.tbi
},
},
// Parse and load the visualization XML configuration
Expand Down
Binary file added packages/locuszoom/test-data/weird.gwas_bgzip
Binary file not shown.
Binary file added packages/locuszoom/test-data/weird.gwas_bgzip.tbi
Binary file not shown.
40 changes: 28 additions & 12 deletions packages/locuszoom/yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,10 @@
"@babel/helper-validator-identifier" "^7.24.7"
to-fast-properties "^2.0.0"

"@esbuild/darwin-arm64@0.25.1":
"@esbuild/linux-x64@0.25.1":
version "0.25.1"
resolved "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.1.tgz"
integrity sha512-5hEZKPf+nQjYoSr/elb62U19/l1mZDdqidGfmFutVUjjUZrOazAtwK+Kr+3y0C/oeJfLlxo9fXb1w7L+P7E4FQ==
resolved "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.1.tgz"
integrity sha512-xbfUhu/gnvSEg+EGovRc+kjBAkrvtk38RlerAzQxvMzlB4fXpCFCeUAYzJvrnhFtdeyVCDANSjJvOvGYoeKzFA==

"@hapi/hoek@^9.0.0":
version "9.3.0"
Expand Down Expand Up @@ -129,15 +129,22 @@
resolved "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz"
integrity sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==

"@playwright/test@^1.58.0":
version "1.58.0"
resolved "https://registry.npmjs.org/@playwright/test/-/test-1.58.0.tgz"
integrity sha512-fWza+Lpbj6SkQKCrU6si4iu+fD2dD3gxNHFhUPxsfXBPhnv3rRSQVd0NtBUT9Z/RhF/boCBcuUaMUSTRTopjZg==
dependencies:
playwright "1.58.0"

"@polka/url@^1.0.0-next.24":
version "1.0.0-next.28"
resolved "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.28.tgz"
integrity sha512-8LduaNlMZGwdZ6qWrKlfa+2M4gahzFkprZiAt2TF8uS0qQgBizKXpXURqvTJ4WtmupWxaLqjRb2UCTe72mu+Aw==

"@rollup/rollup-darwin-arm64@4.35.0":
"@rollup/rollup-linux-x64-gnu@4.35.0":
version "4.35.0"
resolved "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.35.0.tgz"
integrity sha512-Uk+GjOJR6CY844/q6r5DR/6lkPFOw0hjfOIzVx22THJXMxktXG6CbejseJFznU8vHcEBLpiXKY3/6xc+cBm65Q==
resolved "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.35.0.tgz"
integrity sha512-Pim1T8rXOri+0HmV4CdKSGrqcBWX0d1HoPnQ0uw0bdp1aP5SdQVNBy8LjYncvnLgu3fnnCt17xjWGd4cqh8/hA==

"@types/estree@^1.0.0", "@types/estree@1.0.6":
version "1.0.6"
Expand Down Expand Up @@ -1320,11 +1327,6 @@ fs.realpath@^1.0.0:
resolved "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz"
integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==

fsevents@~2.3.2, fsevents@~2.3.3:
version "2.3.3"
resolved "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz"
integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==

function-bind@^1.1.2:
version "1.1.2"
resolved "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz"
Expand Down Expand Up @@ -1660,7 +1662,7 @@ json-stable-stringify-without-jsonify@^1.0.1:
"jszlib@git+https://github.com/dasmoth/jszlib.git#4e562c7":
version "0.2.1"
resolved "git+ssh://git@github.com/dasmoth/jszlib.git"
integrity sha512-L+slw277qqgqWvyz6srOUOqHnbuyLBGPkgzM7IgxCTb/MVTNiy11iQ15mS+dO2f8UIjKBb4z8AgO3vshLrjXVg==
integrity sha512-uvBAyIcKCRxAWN6fpZMzC5GOrFzWsTehZW6DkRn9RKfJ4QcSsHZFqnlFmHQOxSIkO4tWQ0FxGLNKJQ1pKy3PeA==

just-clone@^3.2.1:
version "3.2.1"
Expand Down Expand Up @@ -1976,6 +1978,20 @@ pirates@^4.0.1:
resolved "https://registry.npmjs.org/pirates/-/pirates-4.0.6.tgz"
integrity sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==

playwright-core@1.58.0:
version "1.58.0"
resolved "https://registry.npmjs.org/playwright-core/-/playwright-core-1.58.0.tgz"
integrity sha512-aaoB1RWrdNi3//rOeKuMiS65UCcgOVljU46At6eFcOFPFHWtd2weHRRow6z/n+Lec0Lvu0k9ZPKJSjPugikirw==

playwright@1.58.0:
version "1.58.0"
resolved "https://registry.npmjs.org/playwright/-/playwright-1.58.0.tgz"
integrity sha512-2SVA0sbPktiIY/MCOPX8e86ehA/e+tDNq+e5Y8qjKYti2Z/JG7xnronT/TXTIkKbYGWlCbuucZ6dziEgkoEjQQ==
dependencies:
playwright-core "1.58.0"
optionalDependencies:
fsevents "2.3.2"

postcss-import@^15.1.0:
version "15.1.0"
resolved "https://registry.npmjs.org/postcss-import/-/postcss-import-15.1.0.tgz"
Expand Down