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

End to end testing #711

Open
wants to merge 2 commits into
base: main
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
29 changes: 25 additions & 4 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ services:
- star-net
environment:
- DATABASE_URL=postgresql://postgres:ChangeMeOrDontTest2020@my-db:5432/postgres
- KEYCLOAK_SECRET=${KC_CLIENT_SECRET}

my-db:
image: postgres
ports:
Expand All @@ -19,15 +21,34 @@ services:
- POSTGRES_PASSWORD=ChangeMeOrDontTest2020
restart:
on-failure
kc-db:
image: postgres
expose:
- 5432
environment:
- POSTGRES_PASSWORD=ChangeMeOrDontTest2020



keycloak:
image: quay.io/keycloak/keycloak:23.0.1
command:
- start-dev
- --import-realm
#Docker image corresponds to helm chart version 21.0.3 used in production
#https://github.com/bitnami/charts/commit/35d62114207b5d44b81243b05e9fa62e76709d1a
image: docker.io/bitnami/keycloak:24.0.3-debian-12-r0
ports:
- '8080:8080'
environment:
- KEYCLOAK_ADMIN=admin
- KEYCLOAK_ADMIN_PASSWORD=admin
- WEB_CLIENT_SECRET=${KC_CLIENT_SECRET}
- KEYCLOAK_DATABASE_HOST=kc-db
- KEYCLOAK_DATABASE_PORT=5432
- KEYCLOAK_DATABASE_USER=postgres
- KEYCLOAK_DATABASE_PASSWORD=ChangeMeOrDontTest2020
- KEYCLOAK_DATABASE_NAME=postgres
- KEYCLOAK_EXTRA_ARGS=--import-realm --verbose
volumes:
- ./realm.json:/opt/bitnami/keycloak/data/import/realm.json
depends_on:
- kc-db
networks:
star-net: {}
6 changes: 4 additions & 2 deletions packages/frontend/src/components/DragAndDrop/SortableItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -62,12 +62,14 @@ export function SortableItem({ children, id }: PropsWithChildren<Props>) {
interface DragHandleProps {
style?: CSSProperties;
disabled?: boolean;
ariaLabel?: string;
testId?: string;
}
export function DragHandle({ style, disabled }: DragHandleProps) {
export function DragHandle({ style, disabled, ariaLabel }: DragHandleProps) {
const { attributes, listeners, ref } = useContext(SortableItemContext);

return (
<IconButton {...attributes} {...listeners} ref={ref} style={style} disabled={disabled}>
<IconButton {...attributes} {...listeners} ref={ref} style={style} disabled={disabled} aria-label={ariaLabel}>
<MuiDragHandle />
</IconButton>
);
Expand Down
36 changes: 18 additions & 18 deletions packages/frontend/src/components/Election/ElectionHome.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -75,8 +75,24 @@ const ElectionHome = () => {
{
voterAuth.has_voted == false && voterAuth.authorized_voter && !voterAuth.required &&

<Box display='flex' flexDirection='column' alignItems='center' gap={5} sx={{ p: 1}}>
<Button role='button' name='vote' fullWidth variant='contained' href={`/${String(election?.election_id)}/vote`} >
<Typography align='center' variant="h3" component="h3" fontWeight='bold' sx={{ p: 2 }}>
{t('election_home.vote')}
</Typography>
</Button>
{election.settings.public_results === true &&
<Button variant='text' href={`/${String(election?.election_id)}/results`} >
{t('election_home.or_view_results')}
</Button>
}
</Box>
}
</>}

{election.state === 'draft' && <>
<Box display='flex' flexDirection='column' alignItems='center' gap={5} sx={{ p: 1}}>
<Button fullWidth variant='contained' href={`/${String(election?.election_id)}/vote`} >
<Button role='button' name='vote' fullWidth variant='contained' href={`/${String(election?.election_id)}/vote`} >
<Typography align='center' variant="h3" component="h3" fontWeight='bold' sx={{ p: 2 }}>
{t('election_home.vote')}
</Typography>
Expand All @@ -87,23 +103,7 @@ const ElectionHome = () => {
</Button>
}
</Box>
}
</>}

{election.state === 'draft' && <>
<Box display='flex' flexDirection='column' alignItems='center' gap={5} sx={{ p: 1}}>
<Button fullWidth variant='contained' href={`/${String(election?.election_id)}/vote`} >
<Typography align='center' variant="h3" component="h3" fontWeight='bold' sx={{ p: 2 }}>
{t('election_home.vote')}
</Typography>
</Button>
{election.settings.public_results === true &&
<Button variant='text' href={`/${String(election?.election_id)}/results`} >
{t('election_home.or_view_results')}
</Button>
}
</Box>
</>}
</>}

{election.state === 'closed' && election.end_time &&
<Box sx={{ flexGrow: 1 }}>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import React, { useCallback, useMemo } from 'react';
import { Box, Typography } from '@mui/material';
import { Box, BoxProps, Button, Typography } from '@mui/material';
import { Candidate } from '@equal-vote/star-vote-shared/domain_model/Candidate';
import { IBallotContext } from '../VotePage';
import styled from '@emotion/styled';


interface BubbleGridProps {
Expand All @@ -14,14 +15,21 @@ interface BubbleGridProps {
fontSX: object;
}

const NoStyleButton = styled(Button)({
Copy link
Member

Choose a reason for hiding this comment

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

Is this used?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

No, that was just from trying to get the name prop to work on the bubbles. I must have forgotten to remove it.

all: 'unset',
display: 'inline-block',
cursor: 'pointer',
});


const BubbleGrid: React.FC<BubbleGridProps> = ({ ballotContext, columnValues, columns, numHeaderRows, onClick, makeArea, fontSX }) => {
const { candidates, instructionsRead, alertBubbles } = ballotContext;
// Step 1: Create a triplet of candidateIndex, columnIndex, and columnValue for each candidate

const candidateColumnPairsNested = useMemo(() => {
return candidates.map((_, candidateIndex) =>
return candidates.map((candidate, candidateIndex) =>
columnValues.map((columnValue, columnIndex) =>
[candidateIndex, columnIndex, columnValue]
[candidateIndex, columnIndex, columnValue, candidate.candidate_name] as [number, number, number, string] // Add candidate name for accessibility
)
);
}, [candidates, columnValues]);
Expand All @@ -46,13 +54,14 @@ const BubbleGrid: React.FC<BubbleGridProps> = ({ ballotContext, columnValues, co
// Step 3: Map over the flattened array to render the Box components
return (
<>
{candidateColumnPairsFlat.map(([candidateIndex, columnIndex, columnValue]) => (
<Box
{candidateColumnPairsFlat.map(([candidateIndex, columnIndex, columnValue, candidate_name]) => (
<button
key={`${candidateIndex}-${columnIndex}`}
role='button'
name={`${candidate_name}_rank-${columnValue}`}
className={className(candidateIndex, columnValue)}
onClick={() => onClick(candidateIndex, columnValue)}
sx={{
margin: 'auto',
style={{
//For Rows:
//numHeaderRows offsets grid to account for header rows
//+1 offsets grid to account for candidateIndex starting at 0
Expand All @@ -66,7 +75,7 @@ const BubbleGrid: React.FC<BubbleGridProps> = ({ ballotContext, columnValues, co
<Typography variant='body1' sx={{ ...fontSX }}>
{columns.length === 1 ? ' ' : columnValue}
</Typography>
</Box>
</button>
))
}
</>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ interface ColumnHeadingsProps {
}
export default function ColumnHeadings({ columnIndex, columnTitle, gridArea, starHeadings, fontSX }: ColumnHeadingsProps) {
return (
<Box key={columnIndex} sx={{ gridArea: gridArea }}>
<Box key={columnIndex} sx={{ gridArea: gridArea }}className='column-headings'>
{starHeadings &&
<ScoreIcon
// NOTE: I tried doing this in CSS with :first-child but it didn't work
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ export default function GenericBallotGrid({
{rowBackgrounds}
{/* Column Warnings */}
{ballotContext.warningColumns && ballotContext.warningColumns.map((columnValue, columnIndex) =>
<Box key={columnIndex}
<Box key={columnIndex} aria-label={`warning-skipped-column-${columnValue}`}
sx={{
gridArea: makeArea(1, 1 + columnValue, 1, numHeaderRows + 1 + ballotContext.candidates.length * 2),
height: '100%',
Expand Down
16 changes: 9 additions & 7 deletions packages/frontend/src/components/Election/Voting/VotePage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -187,10 +187,10 @@ const VotePage = () => {
if(pages.length == 0){
return <Container disableGutters={true} maxWidth="sm"><h3>No races created for election</h3></Container>
}

let pageIsUnderVote = (page) => {
return page.candidates.reduce((prev, c) => prev && (c.score == 0 || c.score == null), true)
}
const isOnLastPage = currentPage === pages.length - 1
const noScores = pages.every(page => page.candidates.every(candidate => candidate.score === null))
const thereAreWarnings = pages.some(page => page.warnings)
const submitButtonDisabled = !isOnLastPage || (isPending || noScores || thereAreWarnings)

return (
<Container disableGutters={true} maxWidth="sm">
Expand Down Expand Up @@ -249,9 +249,11 @@ const VotePage = () => {
}
<Button
variant='contained'
onClick={() => (currentPage === pages.length-1)? setIsOpen(true) : setCurrentPageAndScroll(count => count + 1)}
sx={{ maxHeight: '40px', minWidth: '100px', marginLeft: {xs: '10px', md: '40px'}, visibility: 'visible' }}>
{t((currentPage === pages.length-1)? 'ballot.submit_ballot' : 'ballot.next')}
name='submit-ballot'
onClick={() => setIsOpen(true)}
disabled={submitButtonDisabled}//disable unless on last page and at least one candidate scored
Copy link
Member

Choose a reason for hiding this comment

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

Good idea breaking those out into variables, it's much more readable now

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Yeah, it wasn't behaving how it was supposed to do I had to break it into smaller pieces to make it easier to debug

style={{ margin: "auto", minWidth: "150px", marginTop: "40px" }}>
<Typography variant="h6">{t('ballot.submit_ballot')}</Typography>
</Button>
</Box>
<SupportBlurb/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -307,27 +307,36 @@ const CandidateDialog = ({ onEditCandidate, candidate, index, onSave, open, hand
</Dialog>
)
}

export const CandidateForm = ({ onEditCandidate, candidate, index, onDeleteCandidate, disabled, inputRef, onKeyDown}) => {
interface CandidateFormProps {
onEditCandidate: (newCandidate: Candidate) => void,
candidate: Candidate,
index: number,
onDeleteCandidate: () => void,
disabled: boolean,
inputRef: (el: React.MutableRefObject<any[]>) => React.MutableRefObject<any[]>,
onKeyDown: (e: React.KeyboardEvent<HTMLInputElement>) => void,
electionState: string
}
export const CandidateForm = ({ onEditCandidate, candidate, index, onDeleteCandidate, disabled, inputRef, onKeyDown, electionState}: CandidateFormProps) => {

const [open, setOpen] = React.useState(false);
const handleOpen = () => setOpen(true);
const handleClose = () => setOpen(false);
const flags = useFeatureFlags();
const onSave = () => { handleClose() }
return (
<Paper elevation={4} sx={{ width: '100%' }}>
<Paper elevation={4} sx={{ width: '100%' }} aria-label={`candidate-form-${index + 1}`}>
<Box
sx={{ display: 'flex', justifyContent: 'space-between', bgcolor: 'background.paper', borderRadius: 10 }}
alignItems={'center'}
>
<DragHandle style={{marginLeft: 5}} disabled={disabled}/>
<DragHandle style={{marginLeft: 5}} disabled={disabled} ariaLabel={`drag-candidate-number-${index + 1}`}/>

<Box sx={{ overflow: 'hidden', textOverflow: 'ellipsis', width: '100%', pl: 2 }}>
<TextField
id={'candidate-name'}
name="new-candidate-name"
// label={"Candidate Name"}
id={`candidate-name-${index + 1}`}
name={`candidate-name-${index + 1}`}
data-testid={`candidate-name-${index + 1}`}
Copy link
Member

Choose a reason for hiding this comment

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

Looks like there's several parameters being added in order for the tests to retrieve elements (role, aria-label, name, data-testid, etc). Is there a best practice on which one to use when we're writing tests?

It sounds like role and aria-label are things we should be including anyway for making the site screen reader friendly, so I like the idea of tests forcing us to improve the code

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'm not sure, if there is or not. I tried to avoid data-testid as much as possible though to use name, role, or label instead so it would be screen reader friendly

type="text"
value={candidate.candidate_name}
fullWidth
Expand All @@ -336,6 +345,7 @@ export const CandidateForm = ({ onEditCandidate, candidate, index, onDeleteCandi
onChange={(e) => onEditCandidate({ ...candidate, candidate_name: e.target.value })}
inputRef={inputRef}
onKeyDown={onKeyDown}
disabled={electionState !== 'draft'}
/>
</Box>

Expand All @@ -348,7 +358,8 @@ export const CandidateForm = ({ onEditCandidate, candidate, index, onDeleteCandi
</IconButton>
}
<IconButton
aria-label="delete"
aria-label={`delete-candidate-number-${index + 1}`}
name={`delete-${candidate.candidate_name}`}
color="error"
onClick={onDeleteCandidate}
disabled={disabled}>
Expand All @@ -360,7 +371,7 @@ export const CandidateForm = ({ onEditCandidate, candidate, index, onDeleteCandi
)
}

const AddCandidate = ({ onAddNewCandidate }) => {
const AddCandidate = ({ onAddNewCandidate, index }) => {

const handleEnter = (e) => {
saveNewCandidate()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -263,7 +263,7 @@ export default () => {
setErrors={setErrors}
showLabel={false}
/>
<StepButtons activeStep={activeStep} setActiveStep={setActiveStep} canContinue={election.title != '' && errors.title == ''}/>
<StepButtons activeStep={activeStep} setActiveStep={setActiveStep} canContinue={/^[^\s][a-zA-Z0-9\s]{3,49}$/.test(election.title) && errors.title == ''}/>
</StepContent>
</Step>
<Step>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ export const ElectionTitleField = ({termType, value, onUpdateValue, errors, setE
inputProps={{ pattern: "[a-z]{3,15}" }}
error={errors.title !== ''}
required
id="election-name"
name="name"
id="election-title"
name="election-title"
// TODO: This bolding method only works for the text fields, if we like it we should figure out a way to add it to other fields as well
// inputProps={getStyle('title')}
label={showLabel? t('election_details.title') : ""}
Expand Down Expand Up @@ -71,7 +71,7 @@ export default function ElectionDetailsForm({editedElection, applyUpdate, errors
<Grid item xs={12} sx={{ m: 0, p: 1 }}>
<TextField
id="election-description"
name="description"
name="election-description"
label={t('election_details.description')}
multiline
fullWidth
Expand Down Expand Up @@ -125,10 +125,11 @@ export default function ElectionDetailsForm({editedElection, applyUpdate, errors
<>
<Grid item xs={4} sx={{ m: 0, p: 1 }} justifyContent='center'>
<FormControl fullWidth>
<InputLabel id="demo-simple-select-label">{t('election_details.time_zone')}</InputLabel>
<InputLabel id="time-zone-label">{t('election_details.time_zone')}</InputLabel>
<Select
labelId="demo-simple-select-label"
id="demo-simple-select"
labelId="time-zone-label"
id="time-zone-select"
name='edit-time-zone'
value={timeZone}
label={t('election_details.time_zone')}
onChange={(e) => {
Expand All @@ -152,6 +153,8 @@ export default function ElectionDetailsForm({editedElection, applyUpdate, errors
{/* datetime-local is formatted according to the OS locale, I don't think there's a way to override it*/}
<Input
type='datetime-local'
name='edit-start-time'
data-testid='start-time'
error={errors.startTime !== ''}
value={dateToLocalLuxonDate(editedElection.start_time, timeZone)}
onChange={(e) => {
Expand All @@ -176,6 +179,8 @@ export default function ElectionDetailsForm({editedElection, applyUpdate, errors
{/* datetime-local is formatted according to the OS locale, I don't think there's a way to override it*/}
<Input
type='datetime-local'
name='edit-end-time'
data-testid='end-time'
error={errors.endTime !== ''}
value={dateToLocalLuxonDate(editedElection.end_time, timeZone)}
onChange={(e) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,8 @@ export default function ElectionDetailsInlineForm() {

<Box sx={{}}>
<IconButton
aria-label="edit"
aria-label="edit-election-details"
name="edit-election-details"
disabled={election.state!=='draft'}
onClick={handleOpen}>
<EditIcon />
Expand Down
Loading
Loading