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

Api redirect fix #283

Merged
merged 10 commits into from
Sep 6, 2024
Merged
1 change: 1 addition & 0 deletions .github/workflows/PR-validation.yml
Original file line number Diff line number Diff line change
Expand Up @@ -1000,6 +1000,7 @@ jobs:
with:
working-directory: webui/
wait-on: 'http://localhost:3000, http://localhost:8080/api/health'
env: 'API_BASE_URL=http://localhost:8080'
- name: Cleanup webUI server (running container)
working-directory: webui/
run: |
Expand Down
2 changes: 2 additions & 0 deletions webui/Dockerfile.dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
.next/
node_modules/
5 changes: 3 additions & 2 deletions webui/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ REG=${AWS_ACCT_NR}.dkr.ecr.${AWS_DEFAULT_REGION}.amazonaws.com

clean:
$(eval ADDITIONAL_BUILD_ARGS := --no-cache)
@rm -rf .next/
@rm -rf node_modules/

container-image:
Expand Down Expand Up @@ -52,11 +53,11 @@ run-unit-tests: install-deps

run-e2e-tests: install-deps
$(MAKE) --no-print-directory run-container-dev
npx cypress run --e2e || true
npx cypress run --e2e --env API_BASE_URL=${PAVI_API_BASE_URL} || true
$(MAKE) --no-print-directory stop-container-dev

run-e2e-tests-dev: install-deps
npx cypress open --e2e
npx cypress open --e2e --env API_BASE_URL=${PAVI_API_BASE_URL}

stop-container-dev:
@docker compose -f docker-compose-dev.yml --env-file dev.env down agr.pavi.dev-local.webui
44 changes: 44 additions & 0 deletions webui/cypress/e2e/api-rewrite-tests.cy.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/// <reference types="cypress" />

describe('Test API rewrite functionality', () => {
it('/openapi.json response matches API config', () => {

cy.request(`${Cypress.env('API_BASE_URL')}/openapi.json`).then((apiResp) => {

expect(apiResp.status).to.eq(200)

cy.request('/openapi.json').then((webResp) => {
expect(webResp.status).to.eq(200)
expect(JSON.stringify(webResp.body))
.to.eq(JSON.stringify(apiResp.body))
})
})
})

it('Test openAPI UI endpoint execution', () => {

cy.visit('/api/docs')

cy.get('span[data-path="/api/health"').parents('button').as('endpointBtn')
.should('have.length', 1)
.should('be.enabled')
.click()

cy.get('@endpointBtn').parents('div.opblock.is-open').as('operationBlock')

cy.get('@operationBlock').find('button.try-out__btn')
.should('have.length', 1)
.should('be.enabled')
.click()

cy.get('@operationBlock').find('button.execute')
.should('have.length', 1)
.should('be.enabled')
.click()

cy.get('@operationBlock').find('table.live-responses-table')
.should('have.length', 1)
.find('tbody>tr.response>td.response-col_status')
.contains(200)
})
})
134 changes: 67 additions & 67 deletions webui/cypress/e2e/submit-workflow.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,76 +7,76 @@
import formInput from '../fixtures/test-submit-success-input.json'

describe('submit form behaviour', () => {
beforeEach(() => {
// Cypress starts out with a blank slate for each test
// so we must tell it to visit our website with the `cy.visit()` command
// before each test
cy.visit('/')
})

it('tests job submission success', () => {
// We use the `cy.get()` command to get all elements that match the selector.
// There should only be one cell with a inputgroup.
// cy.get('table tbody tr td .p-inputgroup').should('have.length', 1)

// Should displays one alignmentEntry by default.
cy.get('.p-inputgroup').should('have.length', 1)

// There should be excactly one submit button
cy.get('button').filter('[aria-label="Submit"]').as('submitBtn')
cy.get('@submitBtn').should('have.length', 1)

// and it should be disabled by default (on incomplete input).
cy.get('@submitBtn').should('be.disabled')

// There should be excactly one element to click to add records
cy.get('button#add-record').as('addRecordBtn')
cy.get('@addRecordBtn').should('have.length', 1)

// add as many records as there are entries in formInput
for(let i = 1, len = formInput.length; i < len; ++i){
cy.get('@addRecordBtn').click()
}
cy.get('.p-inputgroup').should('have.length', formInput.length)

// Input all data into form
for(let i = 0, len = formInput.length; i < len; ++i){

// Form should be able to receive gene as user input.
cy.get('.p-inputgroup').eq(i).find('input#gene').focus().type(formInput[i].gene)

// Once the transcript list loaded, from should enable selecting the relevant transcripts.
cy.get('.p-inputgroup').eq(i).find('#transcripts').find('input').focus()
cy.get('.p-multiselect-panel').as('openTranscriptsSelectBox').should('be.visible')

// A list of transcript should be available
cy.get('@openTranscriptsSelectBox').find('li.p-multiselect-item').as('openTranscriptsList')
cy.get('@openTranscriptsList').should('have.length.at.least', 1)

// And the relevant transcripts should be selectable
formInput[i].transcripts.forEach((transcript) => {
cy.get('@openTranscriptsList').contains(transcript).click()
})
cy.get('@openTranscriptsSelectBox').find('button.p-multiselect-close').click()

cy.focused().blur()

// Submit button should stay disabled as long a last entry was not submitted
if ( i < len - 1 ) {
beforeEach(() => {
// Cypress starts out with a blank slate for each test
// so we must tell it to visit our website with the `cy.visit()` command
// before each test
cy.visit('/')
})

it('tests job submission success', () => {
// We use the `cy.get()` command to get all elements that match the selector.
// There should only be one cell with a inputgroup.
// cy.get('table tbody tr td .p-inputgroup').should('have.length', 1)

// Should displays one alignmentEntry by default.
cy.get('.p-inputgroup').should('have.length', 1)

// There should be excactly one submit button
cy.get('button').filter('[aria-label="Submit"]').as('submitBtn')
cy.get('@submitBtn').should('have.length', 1)

// and it should be disabled by default (on incomplete input).
cy.get('@submitBtn').should('be.disabled')

if (i === 0) {
cy.wait(5000)
cy.get('@submitBtn').should('be.disabled')
// There should be excactly one element to click to add records
cy.get('button#add-record').as('addRecordBtn')
cy.get('@addRecordBtn').should('have.length', 1)

// add as many records as there are entries in formInput
for(let i = 1, len = formInput.length; i < len; ++i){
cy.get('@addRecordBtn').click()
}
cy.get('.p-inputgroup').should('have.length', formInput.length)

// Input all data into form
for(let i = 0, len = formInput.length; i < len; ++i){

// Form should be able to receive gene as user input.
cy.get('.p-inputgroup').eq(i).find('input#gene').focus().type(formInput[i].gene)

// Once the transcript list loaded, from should enable selecting the relevant transcripts.
cy.get('.p-inputgroup').eq(i).find('#transcripts').find('input').focus()
cy.get('.p-multiselect-panel').as('openTranscriptsSelectBox').should('be.visible')

// A list of transcript should be available
cy.get('@openTranscriptsSelectBox').find('li.p-multiselect-item').as('openTranscriptsList')
cy.get('@openTranscriptsList').should('have.length.at.least', 1)

// And the relevant transcripts should be selectable
formInput[i].transcripts.forEach((transcript) => {
cy.get('@openTranscriptsList').contains(transcript).click()
})
cy.get('@openTranscriptsSelectBox').find('button.p-multiselect-close').click()

cy.focused().blur()

// Submit button should stay disabled as long a last entry was not submitted
if ( i < len - 1 ) {
cy.get('@submitBtn').should('be.disabled')

if (i === 0) {
cy.wait(5000)
cy.get('@submitBtn').should('be.disabled')
}
}
}
}
}

// Submit button should become active after completing all input
cy.get('@submitBtn').should('be.enabled')
// Submit button should become active after completing all input
cy.get('@submitBtn').should('be.enabled')

// Submitting the analysis should report a UUID
cy.get('@submitBtn').click()
cy.contains('div#display-message', /^job .+ is now pending\.$/)
})
// Submitting the analysis should report a UUID
cy.get('@submitBtn').click()
cy.contains('div#display-message', /^job .+ is now pending\.$/)
})
})
48 changes: 24 additions & 24 deletions webui/src/app/components/client/__tests__/AlignmentEntry.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,33 +4,33 @@ import { render } from '@testing-library/react'
import { AlignmentEntry } from '../AlignmentEntry/AlignmentEntry'

jest.mock('https://raw.githubusercontent.com/alliance-genome/agr_ui/main/src/lib/utils.js',
() => {
return {
getSpecies: jest.fn(() => {}),
getSingleGenomeLocation: jest.fn(() => {})
}
},
{virtual: true}
() => {
return {
getSpecies: jest.fn(() => {}),
getSingleGenomeLocation: jest.fn(() => {})
}
},
{virtual: true}
)

describe('AlignmentEntry', () => {
it('renders a gene input element', () => {
const result = render(
<AlignmentEntry index={0} agrjBrowseDataRelease='7.3.0' dispatchInputPayloadPart={jest.fn()} />
)
it('renders a gene input element', () => {
const result = render(
<AlignmentEntry index={0} agrjBrowseDataRelease='7.3.0' dispatchInputPayloadPart={jest.fn()} />
)

const geneInputElement = result.container.querySelector('#gene')
expect(geneInputElement).not.toBe(null) // Expect gene input element to be found
expect(geneInputElement).toHaveClass('p-inputtext') // Expect element to be inputtext box
})
const geneInputElement = result.container.querySelector('#gene')
expect(geneInputElement).not.toBe(null) // Expect gene input element to be found
expect(geneInputElement).toHaveClass('p-inputtext') // Expect element to be inputtext box
})

it('renders transcript input element', () => {
const result = render(
<AlignmentEntry index={0} agrjBrowseDataRelease='7.3.0' dispatchInputPayloadPart={jest.fn()} />
)
const transcriptInputElement = result.container.querySelector('#transcripts')
expect(transcriptInputElement).not.toBe(null) // Expect transcript input element to be found
expect(transcriptInputElement).toHaveClass('p-multiselect') // Expect element to be multiselect box
})
it('renders transcript input element', () => {
const result = render(
<AlignmentEntry index={0} agrjBrowseDataRelease='7.3.0' dispatchInputPayloadPart={jest.fn()} />
)

const transcriptInputElement = result.container.querySelector('#transcripts')
expect(transcriptInputElement).not.toBe(null) // Expect transcript input element to be found
expect(transcriptInputElement).toHaveClass('p-multiselect') // Expect element to be multiselect box
})
})
102 changes: 51 additions & 51 deletions webui/src/app/components/client/__tests__/AlignmentEntryList.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,58 +4,58 @@ import { render, fireEvent } from '@testing-library/react'
import { AlignmentEntryList } from '../AlignmentEntryList/AlignmentEntryList'

jest.mock('https://raw.githubusercontent.com/alliance-genome/agr_ui/main/src/lib/utils.js',
() => {
return {
getSpecies: jest.fn(() => {}),
getSingleGenomeLocation: jest.fn(() => {})
}
},
{virtual: true}
() => {
return {
getSpecies: jest.fn(() => {}),
getSingleGenomeLocation: jest.fn(() => {})
}
},
{virtual: true}
)

describe('AlignmentEntryList', () => {
it('renders one input record by default', () => {
const result = render(
<AlignmentEntryList agrjBrowseDataRelease='7.3.0' dispatchInputPayloadPart={jest.fn()} />
)

const inputGroups = result.container.querySelectorAll('div.p-inputgroup')
expect(inputGroups).toHaveLength(1) // Expect exactly one input group to be found
})

it('renders a functional button to remove individual records', () => {
const result = render(
<AlignmentEntryList agrjBrowseDataRelease='7.3.0' dispatchInputPayloadPart={jest.fn()} />
)

const inputGroupsBefore = result.container.querySelectorAll('div.p-inputgroup')
expect(inputGroupsBefore).toHaveLength(1) // Expect exactly one input group to be found

const removeRecordBtn = result.container.querySelector('button#remove-record')
expect(removeRecordBtn).not.toBeNull() // Expect remove-record button to be found
expect(removeRecordBtn).toBeEnabled()

fireEvent.click(removeRecordBtn!)

//Check one entry-record was removed (zero left)
const inputGroupsAfter = result.container.querySelectorAll('div.p-inputgroup')
expect(inputGroupsAfter).toHaveLength(0) // Expect exactly one input group to be found
})

it('renders a functional add-record button', () => {
const result = render(
<AlignmentEntryList agrjBrowseDataRelease='7.3.0' dispatchInputPayloadPart={jest.fn()} />
)

const addRecordBtn = result.container.querySelector('button#add-record')
expect(addRecordBtn).not.toBeNull() // Expect add-record button to be found
expect(addRecordBtn).toBeEnabled()

//Click the button
fireEvent.click(addRecordBtn!)

//Check one new entry-record was added (two total)
const inputGroups = result.container.querySelectorAll('div.p-inputgroup')
expect(inputGroups).toHaveLength(2) // Expect exactly two input groups to be found
})
it('renders one input record by default', () => {
const result = render(
<AlignmentEntryList agrjBrowseDataRelease='7.3.0' dispatchInputPayloadPart={jest.fn()} />
)

const inputGroups = result.container.querySelectorAll('div.p-inputgroup')
expect(inputGroups).toHaveLength(1) // Expect exactly one input group to be found
})

it('renders a functional button to remove individual records', () => {
const result = render(
<AlignmentEntryList agrjBrowseDataRelease='7.3.0' dispatchInputPayloadPart={jest.fn()} />
)

const inputGroupsBefore = result.container.querySelectorAll('div.p-inputgroup')
expect(inputGroupsBefore).toHaveLength(1) // Expect exactly one input group to be found

const removeRecordBtn = result.container.querySelector('button#remove-record')
expect(removeRecordBtn).not.toBeNull() // Expect remove-record button to be found
expect(removeRecordBtn).toBeEnabled()

fireEvent.click(removeRecordBtn!)

//Check one entry-record was removed (zero left)
const inputGroupsAfter = result.container.querySelectorAll('div.p-inputgroup')
expect(inputGroupsAfter).toHaveLength(0) // Expect exactly one input group to be found
})

it('renders a functional add-record button', () => {
const result = render(
<AlignmentEntryList agrjBrowseDataRelease='7.3.0' dispatchInputPayloadPart={jest.fn()} />
)

const addRecordBtn = result.container.querySelector('button#add-record')
expect(addRecordBtn).not.toBeNull() // Expect add-record button to be found
expect(addRecordBtn).toBeEnabled()

//Click the button
fireEvent.click(addRecordBtn!)

//Check one new entry-record was added (two total)
const inputGroups = result.container.querySelectorAll('div.p-inputgroup')
expect(inputGroups).toHaveLength(2) // Expect exactly two input groups to be found
})
})
Loading