Add cypress test to catch double save issue on room entry creation

This commit is contained in:
Ramon Wenger 2023-12-13 18:04:42 +01:00
parent 66b9f8ac6a
commit eee3bf995c
1 changed files with 212 additions and 163 deletions

View File

@ -1,12 +1,12 @@
import { getMinimalMe } from '../../../support/helpers' import { getMinimalMe } from '../../../support/helpers';
describe('The Room Page (Teacher)', () => { describe('The Room Page (Teacher)', () => {
const MeQuery = getMinimalMe() const MeQuery = getMinimalMe();
const selectedClass = MeQuery.me.selectedClass const selectedClass = MeQuery.me.selectedClass;
const entryText = 'something should be here' const entryText = 'something should be here';
const entryTitle = 'some title' const entryTitle = 'some title';
const slug = 'ein-historisches-festival' const slug = 'ein-historisches-festival';
const id = btoa('RoomNode:1') const id = btoa('RoomNode:1');
const room = { const room = {
id, id,
slug, slug,
@ -15,11 +15,11 @@ describe('The Room Page (Teacher)', () => {
roomEntries: { roomEntries: {
edges: [], edges: [],
}, },
} };
const RoomEntriesQuery = { const RoomEntriesQuery = {
room, room,
} };
const operations = { const operations = {
MeQuery, MeQuery,
@ -46,42 +46,38 @@ describe('The Room Page (Teacher)', () => {
errors: [], errors: [],
}, },
}, },
} };
const checkRadioButton = () => { const checkRadioButton = () => {
cy.get( cy.get('.base-input-container__input:checked + .base-input-container__radiobutton svg').should('have.length', 1);
'.base-input-container__input:checked + .base-input-container__radiobutton svg' };
).should('have.length', 1)
}
beforeEach(() => { beforeEach(() => {
cy.setup() cy.setup();
}) });
it('displays new room entry with author name', () => { it('displays new room entry with author name', () => {
cy.mockGraphqlOps({ cy.mockGraphqlOps({
operations, operations,
}) });
cy.visit(`/room/${slug}`) cy.visit(`/room/${slug}`);
cy.getByDataCy('add-room-entry-button').click() cy.getByDataCy('add-room-entry-button').click();
cy.getByDataCy('add-content-link').first().click() cy.getByDataCy('add-content-link').first().click();
cy.getByDataCy('choose-text-widget').click() cy.getByDataCy('choose-text-widget').click();
cy.getByDataCy('input-with-label-input').type(entryTitle) cy.getByDataCy('input-with-label-input').type(entryTitle);
cy.get('.tip-tap__editor').type(entryText) cy.get('.tip-tap__editor').type(entryText);
cy.getByDataCy('save-button').click() cy.getByDataCy('save-button').click();
cy.get('.room-entry__content:first') cy.get('.room-entry__content:first').should('contain', entryText).should('contain', 'Rachel Green');
.should('contain', entryText) });
.should('contain', 'Rachel Green')
})
// todo: re-enable once cypress can do it correctly // todo: re-enable once cypress can do it correctly
it.skip('changes visibility of a room', () => { it.skip('changes visibility of a room', () => {
const MeQuery = getMinimalMe({ const MeQuery = getMinimalMe({
isTeacher: true, isTeacher: true,
}) });
const operations = { const operations = {
MeQuery, MeQuery,
RoomEntriesQuery, RoomEntriesQuery,
@ -94,50 +90,41 @@ describe('The Room Page (Teacher)', () => {
}, },
}, },
}, },
} };
cy.mockGraphqlOps({ cy.mockGraphqlOps({
operations, operations,
}) });
cy.visit(`/room/${slug}`) cy.visit(`/room/${slug}`);
cy.getByDataCy('room-visibility-status').should('contain', 'alle Lernenden') cy.getByDataCy('room-visibility-status').should('contain', 'alle Lernenden');
cy.getByDataCy('toggle-more-actions-menu').click() cy.getByDataCy('toggle-more-actions-menu').click();
cy.getByDataCy('change-visibility').click() cy.getByDataCy('change-visibility').click();
cy.getByDataCy('modal-title').should('contain', 'Sichtbarkeit anpassen') cy.getByDataCy('modal-title').should('contain', 'Sichtbarkeit anpassen');
cy.get('.change-visibility__radio').should('have.length', 2) cy.get('.change-visibility__radio').should('have.length', 2);
cy.get('.change-visibility__radio--selected').should('have.length', 1) cy.get('.change-visibility__radio--selected').should('have.length', 1);
checkRadioButton() checkRadioButton();
cy.get('.change-visibility__radio--selected') cy.get('.change-visibility__radio--selected').should('have.length', 1).should('contain', 'alle Lernenden');
.should('have.length', 1) checkRadioButton();
.should('contain', 'alle Lernenden') cy.getByDataCy('select-option').eq(0).click();
checkRadioButton() cy.get('.change-visibility__radio--selected').should('have.length', 1);
cy.getByDataCy('select-option').eq(0).click() checkRadioButton();
cy.get('.change-visibility__radio--selected').should('have.length', 1) cy.getByDataCy('select-option').eq(1).click();
checkRadioButton() cy.getByDataCy('select-option').eq(1).click();
cy.getByDataCy('select-option').eq(1).click() cy.get('.change-visibility__radio--selected').should('have.length', 1).should('contain', 'eigenen Beiträge');
cy.getByDataCy('select-option').eq(1).click() checkRadioButton();
cy.get('.change-visibility__radio--selected') cy.getByDataCy('modal-save-button').click();
.should('have.length', 1) cy.getByDataCy('room-visibility-status').should('contain', 'eigenen Beiträge');
.should('contain', 'eigenen Beiträge') cy.getByDataCy('toggle-more-actions-menu').click();
checkRadioButton() cy.getByDataCy('change-visibility').click();
cy.getByDataCy('modal-save-button').click() cy.getByDataCy('modal-title').should('contain', 'Sichtbarkeit anpassen');
cy.getByDataCy('room-visibility-status').should( cy.get('.change-visibility__radio--selected').should('have.length', 1).should('contain', 'eigenen Beiträge');
'contain', checkRadioButton();
'eigenen Beiträge' });
)
cy.getByDataCy('toggle-more-actions-menu').click()
cy.getByDataCy('change-visibility').click()
cy.getByDataCy('modal-title').should('contain', 'Sichtbarkeit anpassen')
cy.get('.change-visibility__radio--selected')
.should('have.length', 1)
.should('contain', 'eigenen Beiträge')
checkRadioButton()
})
it('deletes the room and goes back to the overview', () => { it('deletes the room and goes back to the overview', () => {
const MeQuery = getMinimalMe() const MeQuery = getMinimalMe();
const schoolClass = MeQuery.me.selectedClass const schoolClass = MeQuery.me.selectedClass;
const roomToDelete = { const roomToDelete = {
id: window.btoa('RoomNode:room-to-delete'), id: window.btoa('RoomNode:room-to-delete'),
title: 'Delete Me', title: 'Delete Me',
@ -146,20 +133,20 @@ describe('The Room Page (Teacher)', () => {
roomEntries: { roomEntries: {
edges: [], edges: [],
}, },
} };
const otherRoom = { const otherRoom = {
id: window.btoa('RoomNode:otherRoom'), id: window.btoa('RoomNode:otherRoom'),
slug: 'other-slug', slug: 'other-slug',
title: 'Other Room', title: 'Other Room',
schoolClass, schoolClass,
} };
let rooms = [roomToDelete, otherRoom] let rooms = [roomToDelete, otherRoom];
const operations = { const operations = {
MeQuery, MeQuery,
RoomsQuery() { RoomsQuery() {
return { return {
rooms, rooms,
} };
}, },
RoomEntriesQuery: { RoomEntriesQuery: {
room: roomToDelete, room: roomToDelete,
@ -169,32 +156,32 @@ describe('The Room Page (Teacher)', () => {
success: true, success: true,
}, },
}, },
} };
cy.mockGraphqlOps({ cy.mockGraphqlOps({
operations, operations,
}) });
cy.visit(`/rooms`) cy.visit(`/rooms`);
cy.getByDataCy('room-widget').should('have.length', 2) cy.getByDataCy('room-widget').should('have.length', 2);
cy.getByDataCy('room-widget').first().click() cy.getByDataCy('room-widget').first().click();
cy.getByDataCy('room-title').should('contain', 'Delete Me') cy.getByDataCy('room-title').should('contain', 'Delete Me');
cy.getByDataCy('toggle-more-actions-menu').click() cy.getByDataCy('toggle-more-actions-menu').click();
cy.getByDataCy('delete-room').within(() => { cy.getByDataCy('delete-room').within(() => {
cy.get('a').click() cy.get('a').click();
}) });
cy.getByDataCy('modal-save-button').click() cy.getByDataCy('modal-save-button').click();
cy.url().should('include', 'rooms') cy.url().should('include', 'rooms');
cy.getByDataCy('room-widget').should('have.length', 1) cy.getByDataCy('room-widget').should('have.length', 1);
}) });
it('changes class while on room page', () => { it('changes class while on room page', () => {
const { me } = MeQuery const { me } = MeQuery;
const otherClass = { const otherClass = {
id: window.btoa('SchoolClassNode:34'), id: window.btoa('SchoolClassNode:34'),
name: 'Other Class', name: 'Other Class',
readOnly: false, readOnly: false,
} };
let selectedClass = me.selectedClass let selectedClass = me.selectedClass;
const operations = { const operations = {
MeQuery: () => { MeQuery: () => {
return { return {
@ -203,16 +190,16 @@ describe('The Room Page (Teacher)', () => {
schoolClasses: [...me.schoolClasses, otherClass], schoolClasses: [...me.schoolClasses, otherClass],
selectedClass, selectedClass,
}, },
} };
}, },
RoomEntriesQuery, RoomEntriesQuery,
UpdateSettings() { UpdateSettings() {
selectedClass = otherClass selectedClass = otherClass;
return { return {
updateSettings: { updateSettings: {
success: true, success: true,
}, },
} };
}, },
ModuleDetailsQuery: {}, ModuleDetailsQuery: {},
MySchoolClassQuery: () => { MySchoolClassQuery: () => {
@ -220,32 +207,32 @@ describe('The Room Page (Teacher)', () => {
me: { me: {
selectedClass, selectedClass,
}, },
} };
}, },
RoomsQuery: { RoomsQuery: {
rooms: [], rooms: [],
}, },
} };
cy.mockGraphqlOps({ cy.mockGraphqlOps({
operations, operations,
}) });
cy.visit(`/room/${slug}`) cy.visit(`/room/${slug}`);
cy.getByDataCy('room-title').should('contain', 'A Room') cy.getByDataCy('room-title').should('contain', 'A Room');
cy.selectClass('Other Class') cy.selectClass('Other Class');
cy.url().should('include', 'rooms') cy.url().should('include', 'rooms');
cy.getByDataCy('current-class-name').should('contain', 'Other Class') cy.getByDataCy('current-class-name').should('contain', 'Other Class');
}) });
}) });
describe('The Room Page (student)', () => { describe('The Room Page (student)', () => {
const slug = 'ein-historisches-festival' const slug = 'ein-historisches-festival';
const MeQuery = getMinimalMe({ isTeacher: false }) const MeQuery = getMinimalMe({ isTeacher: false });
const { me } = MeQuery const { me } = MeQuery;
const id = atob(me.id).split(':')[1] const id = atob(me.id).split(':')[1];
const authorId = btoa(`PublicUserNode:${id}`) const authorId = btoa(`PublicUserNode:${id}`);
const entrySlug = 'entry-slug' const entrySlug = 'entry-slug';
const { selectedClass } = me const { selectedClass } = me;
const roomEntry = { const roomEntry = {
id: 'entry-id', id: 'entry-id',
slug: entrySlug, slug: entrySlug,
@ -266,7 +253,7 @@ describe('The Room Page (student)', () => {
lastName: 'Was Heiri', lastName: 'Was Heiri',
avatarUrl: '', avatarUrl: '',
}, },
} };
const room = { const room = {
id, id,
slug, slug,
@ -279,58 +266,120 @@ describe('The Room Page (student)', () => {
}, },
], ],
}, },
} };
const RoomEntriesQuery = { const RoomEntriesQuery = {
room, room,
} };
beforeEach(() => { beforeEach(() => {
cy.setup() cy.setup();
}) });
it('room actions should not exist for student', () => { it('room actions should not exist for student', () => {
const operations = { const operations = {
MeQuery: getMinimalMe({ isTeacher: false }), MeQuery: getMinimalMe({ isTeacher: false }),
RoomEntriesQuery, RoomEntriesQuery,
} };
cy.mockGraphqlOps({ cy.mockGraphqlOps({
operations, operations,
}) });
cy.visit(`/room/${slug}`) cy.visit(`/room/${slug}`);
cy.getByDataCy('room-title').should('exist') cy.getByDataCy('room-title').should('exist');
cy.getByDataCy('room-actions').should('not.exist') cy.getByDataCy('room-actions').should('not.exist');
}) });
it('creates a room entry', () => { it('creates a room entry', () => {
const MeQuery = getMinimalMe({ isTeacher: false }) const MeQuery = getMinimalMe({ isTeacher: false });
const room = { const room = {
id: 'some-room', id: 'some-room',
roomEntries: { roomEntries: {
edges: [], edges: [],
}, },
} };
const operations = { const operations = {
MeQuery, MeQuery,
RoomEntriesQuery: { RoomEntriesQuery: {
room, room,
}, },
} };
cy.mockGraphqlOps({ cy.mockGraphqlOps({
operations, operations,
}) });
cy.visit(`/room/${slug}`) cy.visit(`/room/${slug}`);
cy.getByDataCy('add-room-entry-button').click() cy.getByDataCy('add-room-entry-button').click();
cy.getByDataCy('content-form-section-title').should( cy.getByDataCy('content-form-section-title').should('have.text', 'Titel (Pflichtfeld)');
'have.text', });
'Titel (Pflichtfeld)'
) it.only('creates a room entry and presses "Save" twice', () => {
}) const MeQuery = getMinimalMe({ isTeacher: false });
const room = {
id: 'some-room',
roomEntries: {
edges: [],
},
};
const operations = {
MeQuery,
RoomEntriesQuery: {
room,
},
AddRoomEntry: () => {
return new Promise((resolve) => {
// simulate a slow-ish connection
setTimeout(() => {
resolve({
addRoomEntry: {
roomEntry: {
slug: 'entry-slug',
title: 'Some Title',
contents: [
{
type: 'text_block',
value: {
text: 'Redrum!',
},
},
],
author: {
firstName: 'Stephen',
lastName: 'King',
id: window.btoa('PublicUserNode:stephen-king'),
},
},
},
});
}, 500);
});
},
};
cy.mockGraphqlOps({
operations,
});
cy.visit(`/room/${slug}`);
cy.getByDataCy('add-room-entry-button').click();
cy.getByDataCy('content-form-section-title').should('have.text', 'Titel (Pflichtfeld)');
cy.getByDataCy('content-block-title').within(() => {
cy.getByDataCy('input-with-label-input').type('Title');
});
cy.getByDataCy('add-content-link').click();
cy.getByDataCy('choose-text-widget').click();
cy.get('.tip-tap__editor').type('Some text');
cy.getByDataCy('save-button').click();
cy.getByDataCy('save-button').click();
cy.getByDataCy('room-title').should('contain', 'A Room');
cy.wait(1000); // wait for both requests to finish, if there's more than one
cy.getByDataCy('room-entry').should('have.length', 1);
});
it('edits own room entry', () => { it('edits own room entry', () => {
const room = { const room = {
@ -344,7 +393,7 @@ describe('The Room Page (student)', () => {
}, },
], ],
}, },
} };
const operations = { const operations = {
MeQuery: MeQuery, MeQuery: MeQuery,
RoomEntriesQuery: { RoomEntriesQuery: {
@ -353,15 +402,15 @@ describe('The Room Page (student)', () => {
RoomEntryQuery: { RoomEntryQuery: {
roomEntry, roomEntry,
}, },
} };
cy.mockGraphqlOps({ cy.mockGraphqlOps({
operations, operations,
}) });
cy.visit(`/room/${slug}`) cy.visit(`/room/${slug}`);
cy.getByDataCy('room-entry-actions').click() cy.getByDataCy('room-entry-actions').click();
cy.getByDataCy('edit-room-entry').click() cy.getByDataCy('edit-room-entry').click();
cy.location('pathname').should('include', entrySlug) cy.location('pathname').should('include', entrySlug);
}) });
it('deletes room entry', () => { it('deletes room entry', () => {
const DeleteRoomEntry = { const DeleteRoomEntry = {
@ -370,57 +419,57 @@ describe('The Room Page (student)', () => {
errors: null, errors: null,
roomSlug: slug, roomSlug: slug,
}, },
} };
const operations = { const operations = {
MeQuery, MeQuery,
RoomEntriesQuery, RoomEntriesQuery,
DeleteRoomEntry, DeleteRoomEntry,
} };
cy.mockGraphqlOps({ cy.mockGraphqlOps({
operations, operations,
}) });
cy.visit(`/room/${slug}`) cy.visit(`/room/${slug}`);
cy.getByDataCy('room-entry').should('have.length', 1) cy.getByDataCy('room-entry').should('have.length', 1);
cy.getByDataCy('room-entry-actions').click() cy.getByDataCy('room-entry-actions').click();
cy.getByDataCy('delete-room-entry').click() cy.getByDataCy('delete-room-entry').click();
cy.getByDataCy('delete-room-entry').should('not.exist') cy.getByDataCy('delete-room-entry').should('not.exist');
cy.getByDataCy('modal-save-button').click() cy.getByDataCy('modal-save-button').click();
cy.getByDataCy('room-entry').should('have.length', 0) cy.getByDataCy('room-entry').should('have.length', 0);
}) });
it('shows room entries with comment count', () => { it('shows room entries with comment count', () => {
const operations = { const operations = {
MeQuery, MeQuery,
RoomEntriesQuery, RoomEntriesQuery,
} };
cy.mockGraphqlOps({ cy.mockGraphqlOps({
operations, operations,
}) });
cy.visit(`/room/${slug}`) cy.visit(`/room/${slug}`);
cy.getByDataCy('room-entry') cy.getByDataCy('room-entry')
.should('have.length', 1) .should('have.length', 1)
.within(() => { .within(() => {
cy.getByDataCy('entry-count').should('contain.text', '2') cy.getByDataCy('entry-count').should('contain.text', '2');
}) });
}) });
it('does not show actions on mobile', () => { it('does not show actions on mobile', () => {
const operations = { const operations = {
MeQuery, MeQuery,
RoomEntriesQuery, RoomEntriesQuery,
} };
cy.mockGraphqlOps({ cy.mockGraphqlOps({
operations, operations,
}) });
cy.viewport('iphone-8') cy.viewport('iphone-8');
cy.visit(`/room/${slug}`) cy.visit(`/room/${slug}`);
cy.getByDataCy('room-actions').should('not.exist') cy.getByDataCy('room-actions').should('not.exist');
cy.getByDataCy('room-entry').should('have.length', 1) cy.getByDataCy('room-entry').should('have.length', 1);
cy.getByDataCy('room-entry-actions').should('not.be.visible') cy.getByDataCy('room-entry-actions').should('not.be.visible');
}) });
}) });