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

[tests] tests: add tests for the comparison buttons #2029

Merged
merged 8 commits into from
Nov 28, 2024
10 changes: 10 additions & 0 deletions frontend/.env.development
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,15 @@ REACT_APP_CSP_IMAGE_SRC="https://i.ytimg.com https://www.paypal.com https://www.
# 'unsafe-inline' is added here for development purposes only (used by hot reloading)
REACT_APP_CSP_SCRIPT_SRC="'unsafe-inline' https://www.youtube.com/iframe_api https://www.youtube.com/s/player/"

#
# Debug and development flags
#

# Enable the control of the displayed comparison inputs using a URL parameter.
REACT_APP_ENABLE_COMP_DEBUG_INPUT=true

#
# Tournesol feature flags
#

REACT_APP_POLL_PRESIDENTIELLE_2022_ENABLED=true
1 change: 1 addition & 0 deletions frontend/.env.test
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ REACT_APP_WEBSITE_ANALYTICS_URL=

# Tournesol API configuration
REACT_APP_API_URL=http://localhost:8000

REACT_APP_OAUTH_CLIENT_ID=YlfkLzvVjmGw3gjJzdlFuMFWcR64fAk4WNg5ucGg
REACT_APP_OAUTH_CLIENT_SECRET=iB9j9hM5ekFpKlZQ6uNGloFJIWLVnq8LoG7SNdCtHY5oM7w9KY0XjpaDuwwJ40BshH7jKYZmXniaybhrQf5p4irAOMWv82RdYRMD6TTSJciZEAxn9onpKQoUgUeDqsRj

Expand Down
11 changes: 10 additions & 1 deletion frontend/src/features/comparisons/ComparisonInput.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import React, { useContext, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { useLocation } from 'react-router-dom';

import {
Alert,
Expand Down Expand Up @@ -76,6 +77,8 @@ const ComparisonInput = ({
const { t } = useTranslation();
const { options, criterias } = useCurrentPoll();
const comparisonsContext = useContext(ComparisonsContext);
const location = useLocation();

const pointerFine = useMediaQuery('(pointer:fine)', { noSsr: true });

// Position of the displayed criterion in the list of criteria.
Expand All @@ -86,9 +89,15 @@ const ComparisonInput = ({
options?.mainCriterionName
);

const debugInput = new URLSearchParams(location.search).get('debugInput');
const buttonsDebugEnabled =
import.meta.env.REACT_APP_ENABLE_COMP_DEBUG_INPUT &&
debugInput === 'buttons';

const buttonsUsed = mainScoreMax == BUTTON_SCORE_MAX;
const slidersUsed = mainScoreMax == SLIDER_SCORE_MAX;
const fallBackToButtons = !buttonsUsed && !slidersUsed && !pointerFine;
const fallBackToButtons =
!buttonsUsed && !slidersUsed && (!pointerFine || buttonsDebugEnabled);

const changePosition = (newPos: number) => {
setPosition(newPos);
Expand Down
4 changes: 2 additions & 2 deletions frontend/src/features/comparisons/inputs/CriteriaButtons.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -218,7 +218,7 @@ const CriteriaButtons = ({
>
<MobileIconButton
color="secondary"
aria-label={t('comparisonCriteriaButtons.nextQualityCriterion')}
aria-label={t('comparisonCriteriaButtons.previousQualityCriterion')}
onClick={() => moveWithoutPatching('down')}
disabled={disableScoreButtons || navigationDisabled}
>
Expand Down Expand Up @@ -265,7 +265,7 @@ const CriteriaButtons = ({
>
<MobileIconButton
color="secondary"
aria-label={t('comparisonCriteriaButtons.previousQualityCriterion')}
aria-label={t('comparisonCriteriaButtons.nextQualityCriterion')}
onClick={() => moveWithoutPatching('up')}
disabled={disableScoreButtons || navigationDisabled}
>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,13 +68,16 @@ const ScoreButton = ({
onClick,
}: ScoreButtonProps) => {
const theme = useTheme();
const hover = useMediaQuery('(hover: hover)');
const hover = useMediaQuery('(pointer:fine) and (hover:hover)');

return (
<IconButton
disabled={disabled}
color="secondary"
onClick={() => onClick(score)}
data-criterion-input-type="score-button"
data-criterion-input-score={score}
data-criterion-input-selected={selected}
sx={{
minWidth: '40px',
borderRadius: '4px',
Expand Down
70 changes: 11 additions & 59 deletions tests/cypress/e2e/frontend/comparisonPage.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,61 +33,13 @@ describe('Comparison page', () => {
});
};

const deleteComparison = (idA, idB) => {
cy.sql(`
DELETE FROM tournesol_comparisoncriteriascore
WHERE comparison_id = (
SELECT id
FROM tournesol_comparison
WHERE entity_1_id = (
SELECT id FROM tournesol_entity WHERE metadata->>'video_id' = '${idA}'
) AND entity_2_id = (
SELECT id FROM tournesol_entity WHERE metadata->>'video_id' = '${idB}'
) AND user_id = (
SELECT id FROM core_user WHERE username = '${username}'
)
);
`);

cy.sql(`
DELETE FROM tournesol_comparison
WHERE entity_1_id = (
SELECT id FROM tournesol_entity WHERE metadata->>'video_id' = '${idA}'
) AND entity_2_id = (
SELECT id FROM tournesol_entity WHERE metadata->>'video_id' = '${idB}'
) AND user_id = (
SELECT id FROM core_user WHERE username = '${username}'
);
`);
};

const deleteComparisons = () => {
cy.sql(`
DELETE FROM tournesol_comparisoncriteriascore
WHERE comparison_id IN (
SELECT id
FROM tournesol_comparison
WHERE user_id = (
SELECT id FROM core_user WHERE username = '${username}'
)
);
`);

cy.sql(`
DELETE FROM tournesol_comparison
WHERE user_id = (
SELECT id FROM core_user WHERE username = '${username}'
);
`);
};

before(() => { // create 4 comparisons to avoid being in the tutorial context
cy.recreateUser(username, "test-comparison-page@example.com", "tournesol");
createComparisons();
});

after(() => {
deleteComparisons();
cy.deleteAllComparisonsOfUser(username);
});

const waitForAutoFill = () => {
Expand Down Expand Up @@ -277,8 +229,8 @@ describe('Comparison page', () => {
});

describe('submit a comparison', () => {
const videoAId = 'u83A7DUNMHs';
const videoBId = '6jK9bFWE--g';
const uidA = 'yt:u83A7DUNMHs';
const uidB = 'yt:6jK9bFWE--g';

const optionalCriteriaSliders = [
"slider_expert_reliability",
Expand All @@ -293,11 +245,11 @@ describe('Comparison page', () => {
];

beforeEach(() => {
deleteComparison(videoAId, videoBId);
cy.deleteOneComparisonOfUser(username, uidA, uidB);
});

after(() => {
deleteComparison(videoAId, videoBId);
cy.deleteOneComparisonOfUser(username, uidA, uidB);
});

/**
Expand All @@ -319,10 +271,10 @@ describe('Comparison page', () => {

// add one video, and ask for a second one
cy.get("[data-testid=entity-select-button-compact]").first().click();
pasteInVideoInput(`yt:${videoAId}`);
pasteInVideoInput(uidA);

cy.get("[data-testid=entity-select-button-compact]").last().click();
pasteInVideoInput(`yt:${videoBId}`);
pasteInVideoInput(uidB);

// only one criteria must be visible by default
cy.contains('add optional criteria', {matchCase: false})
Expand Down Expand Up @@ -354,9 +306,9 @@ describe('Comparison page', () => {
waitForAutoFill();

cy.get("[data-testid=entity-select-button-compact]").first().click();
pasteInVideoInput(`yt:${videoAId}`);
pasteInVideoInput(uidA);
cy.get("[data-testid=entity-select-button-compact]").last().click();
pasteInVideoInput(`yt:${videoBId}`);
pasteInVideoInput(uidB);

cy.contains('add optional criteria', {matchCase: false}).click();

Expand Down Expand Up @@ -389,9 +341,9 @@ describe('Comparison page', () => {
waitForAutoFill();

cy.get("[data-testid=entity-select-button-compact]").first().click();
pasteInVideoInput(`yt:${videoAId}`);
pasteInVideoInput(uidA);
cy.get("[data-testid=entity-select-button-compact]").last().click();
pasteInVideoInput(`yt:${videoAId}`);
pasteInVideoInput(uidA);

cy.contains('These two items are very similar', {matchCase: false})
.should('be.visible');
Expand Down
119 changes: 119 additions & 0 deletions tests/cypress/e2e/frontend/comparisonPageInputButtons.cy.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
describe('Comparison page w/ criteria buttons', () => {
const username = 'test-comp-input-buttons';
const ids1 = ['yt:hdAEGAwlK0M', 'yt:lYXQvHhfKuM'];
const ids2 = ['yt:sGLiSLAlwrY', 'yt:or5WdufFrmI'];

// This comparison should not be created during the setup.
const newComparison = ['yt:sAjm3-IaRtI', 'yt:IVqXKP91L4E'];

const criteriaNames = [
'should be largely recommended',
'reliable & not misleading',
'clear & pedagogical',
'important & actionable',
'layman-friendly',
'entertaining & relaxing',
'engaging & thought-provoking',
'diversity & inclusion',
'encourages better habits',
'resilience to backfiring risks',
]

/**
* Create as much comparisons as required to not trigger the tutorial.
*/
const createComparisons = () => {
ids1.forEach(uid1 => {
ids2.forEach(uid2 => {

cy.sql(`
WITH ent AS (
SELECT
(SELECT id FROM tournesol_entity WHERE uid = '${uid1}') AS id1,
(SELECT id FROM tournesol_entity WHERE uid = '${uid2}') AS id2
)
INSERT INTO tournesol_comparison (
user_id,
entity_1_id,
entity_2_id,
entity_1_2_ids_sorted,
poll_id
) VALUES (
(SELECT id FROM core_user WHERE username = '${username}'),
(SELECT id1 FROM ent),
(SELECT id2 FROM ent),
(SELECT id1 FROM ent) || '__' || (SELECT id2 FROM ent),
1);
`);
});
});
};

before(() => {
cy.recreateUser(username, `${username}@example.com`, 'tournesol');
createComparisons();
});

afterEach(() => {
cy.deleteOneComparisonOfUser(username, newComparison[0], newComparison[1]);
});

after(() => {
cy.deleteAllComparisonsOfUser(username);
cy.deleteUser(username);
});

it('allows to do a partial comparison', () => {
cy.visit(`/comparison?uidA=${newComparison[0]}&uidB=${newComparison[1]}&debugInput=buttons`);
cy.focused().type(username);
cy.get('input[name="password"]').click().type('tournesol').type('{enter}');

// The optional criteria button should not be displayed.
cy.contains('add optional criteria', {matchCase: false}).should('not.exist');

// 5 score buttons are displayed for the current criterion.
cy.contains('should be largely recommended', {matchCase: false}).should('be.visible');
cy.get('[data-criterion-input-type="score-button"]').should('have.length', 5);
[-2, -1, 0, 1, 2].forEach((score) => {
cy.get(`[data-criterion-input-score="${score}"]`).should('be.visible');
});

cy.get('[data-criterion-input-score="1"]').click();
cy.contains('successfully submitted', {matchCase: false})
.should('be.visible');

cy.contains('should be largely recommended', {matchCase: false}).should('not.exist');
cy.contains('reliable & not misleading', {matchCase: false}).should('be.visible');

cy.get('button[aria-label="Previous quality criterion"]').click().click().click();
cy.contains('reliable & not misleading', {matchCase: false}).should('not.exist');
cy.contains('encourages better habits', {matchCase: false}).should('be.visible');

[
'resilience to backfiring risks',
...criteriaNames.slice(0 ,8)
].forEach((criterion) => {
cy.get('button[aria-label="Next quality criterion"]').click();
cy.contains(criterion, {matchCase: false}).should('be.visible');
});

cy.get('button[aria-label="Next quality criterion"]').click().click().click();
cy.contains('should be largely recommended', {matchCase: false}).should('be.visible');
});

it('allows to do a full comparison', () => {
cy.visit(`/comparison?uidA=${newComparison[0]}&uidB=${newComparison[1]}&debugInput=buttons`);
cy.focused().type(username);
cy.get('input[name="password"]').click().type('tournesol').type('{enter}');

criteriaNames.forEach(() => {
cy.get('[data-criterion-input-score="-2"]').click();
});

criteriaNames.forEach(() => {
cy.get('[data-criterion-input-score="-2"][data-criterion-input-selected="true"]')
.should('exist');
cy.get('button[aria-label="Next quality criterion"]').click();
});
});
});
54 changes: 54 additions & 0 deletions tests/cypress/support/commands.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,3 +50,57 @@ from core.models import User
User.objects.filter(username='${username}').delete()
"`)
)

/**
* Delete a single comparison made by a given user.
*/
Cypress.Commands.add('deleteOneComparisonOfUser', (username, uidA, uidB) => {
cy.sql(`
DELETE FROM tournesol_comparisoncriteriascore
WHERE comparison_id = (
SELECT id
FROM tournesol_comparison
WHERE entity_1_id = (
SELECT id FROM tournesol_entity WHERE uid = '${uidA}'
) AND entity_2_id = (
SELECT id FROM tournesol_entity WHERE uid = '${uidB}'
) AND user_id = (
SELECT id FROM core_user WHERE username = '${username}'
)
);
`);

GresilleSiffle marked this conversation as resolved.
Show resolved Hide resolved
cy.sql(`
DELETE FROM tournesol_comparison
WHERE entity_1_id = (
SELECT id FROM tournesol_entity WHERE uid = '${uidA}'
) AND entity_2_id = (
SELECT id FROM tournesol_entity WHERE uid = '${uidB}'
) AND user_id = (
SELECT id FROM core_user WHERE username = '${username}'
);
`);
});

/**
* Delete all comparisons made by a given user.
*/
Cypress.Commands.add('deleteAllComparisonsOfUser', (username) => {
cy.sql(`
DELETE FROM tournesol_comparisoncriteriascore
WHERE comparison_id IN (
SELECT id
FROM tournesol_comparison
WHERE user_id = (
SELECT id FROM core_user WHERE username = '${username}'
)
);
`);

cy.sql(`
DELETE FROM tournesol_comparison
WHERE user_id = (
SELECT id FROM core_user WHERE username = '${username}'
);
`);
});
Loading