diff --git a/client/cypress/fixtures/mocks.js b/client/cypress/fixtures/mocks.js index d54c15ce..bd2e669d 100644 --- a/client/cypress/fixtures/mocks.js +++ b/client/cypress/fixtures/mocks.js @@ -1,11 +1,11 @@ export default { UUID: () => '123-456-789', - GenericStreamFieldType: () => 'GenericStreamFieldType', + GenericStreamFieldType: () => ({type: 'text_block', value: 'Generic Stream Field Type'}), DateTime: () => '2021-01-01Z10:01:23', SnapshotNode: () => ({ // id: ID! // module: ModuleNode! - chapters: [], + chapters: [], // chapters: [SnapshotChapterNode] // hiddenContentBlocks(offset: Int, before: String, after: String, first: Int, last: Int, slug: String, title: String): ContentBlockNodeConnection! // created: DateTime! @@ -13,13 +13,31 @@ export default { // shared: Boolean! // objectiveGroups: [SnapshotObjectiveGroupNode] // hiddenObjectives(offset: Int, before: String, after: String, first: Int, last: Int, text: String): ObjectiveNodeConnection! - title: 'MockSnapshotTitle', - metaTitle: 'MockSnapshotMetaTitle' + title: 'MockSnapshotTitle', + metaTitle: 'MockSnapshotMetaTitle', // heroImage: String // changes: SnapshotChangesNode // mine: Boolean }), + ChapterNode: () => ({ + slug: 'chapter-slug', + id: 'chapter-id', + title: 'chapter-title', + description: 'chapter-description', + + }), ContentBlockNode: () => ({ contents: [], + title: 'content-block-title', + slug: 'content-block-slug', + userCreated: false, + type: '', + id: 'content-block-id', + }), + AssignmentNode: () => ({ + id: 'assignment-id', + title: 'Assignment Title', + assignment: 'Assignment Text', + solution: 'Assignment Solution', }), }; diff --git a/client/cypress/integration/frontend/assignment-feedback-read-only.teacher.spec.js b/client/cypress/integration/frontend/assignment-feedback-read-only.teacher.spec.js new file mode 100644 index 00000000..2a799e78 --- /dev/null +++ b/client/cypress/integration/frontend/assignment-feedback-read-only.teacher.spec.js @@ -0,0 +1,68 @@ +import mocks from '../../fixtures/mocks'; + +const myText = 'Mein Feedback'; + +const getOperations = ({readOnly}) => ({ + MeQuery: { + me: { + onboardingVisited: true, + readOnly, + }, + }, + StudentSubmissions: { + studentSubmission: { + id: 'id', + text: 'Submission Text', + document: '', + student: { + firstName: 'Peter', + lastName: 'Student', + }, + assignment: { + title: 'Assignment Title', + assignment: 'Assignment Text', + }, + submissionFeedback: { + id: 'feedback-id', + text: myText, + final: true, + }, + }, + }, +}); + +describe('Assignment feedback read-only - Teacher', () => { + beforeEach(() => { + cy.fakeLogin('nico.teacher', 'test'); + cy.server(); + cy.task('getSchema').then(schema => { + cy.mockGraphql({ + schema, + mocks, + }); + }); + }); + + it('can not edit', () => { + cy.mockGraphqlOps({ + operations: getOperations({readOnly: true}), + }); + + cy.visit('submission/submission-id'); + // cy.get('.submission-form__textarea--readonly').as('textarea'); + // + // cy.get('@textarea').invoke('val').should('contain', myText); + // cy.get('@textarea').should('have.attr', 'readonly'); + + cy.isSubmissionReadOnly(myText); + cy.canReopen(false); + }); + it('can edit', () => { + cy.mockGraphqlOps({ + operations: getOperations({readOnly: false}), + }); + + cy.visit('submission/submission-id'); + cy.canReopen(false); + }); +}); diff --git a/client/cypress/integration/frontend/assignment-read-only.student.spec.js b/client/cypress/integration/frontend/assignment-read-only.student.spec.js new file mode 100644 index 00000000..49b7b4e7 --- /dev/null +++ b/client/cypress/integration/frontend/assignment-read-only.student.spec.js @@ -0,0 +1,115 @@ +import mocks from '../../fixtures/mocks'; +import minimalModule from '../../fixtures/module.minimal'; + +const module = { + ...minimalModule, + chapters: [ + { + contentBlocks: [ + { + type: 'task', + contents: [ + { + type: 'text_block', + value: { + text: 'hallo velo', + }, + id: 'bla-123', + }, + { + type: 'assignment', + value: { + title: 'assignment-title', + assignment: 'assignment-assignment', + id: 'some-assignment', + }, + id: '123-456', + }, + ], + }, + ], + }, + ], +}; + +const myText = 'submission text'; + +const getOperations = ({final, readOnly}) => ({ + MeQuery: { + me: { + onboardingVisited: true, + readOnly + }, + }, + ModuleDetailsQuery: { + module, + }, + AssignmentQuery: { + assignment: { + submission: { + text: myText, + final, + document: '', + submissionFeedback: null + }, + }, + }, +}); + +describe('Assignments read-only - Student', () => { + beforeEach(() => { + cy.fakeLogin('rahel.cueni', 'test'); + cy.server(); + cy.task('getSchema').then(schema => { + cy.mockGraphql({ + schema, + mocks + }); + }); + }); + + it('can edit and turn in', () => { + cy.mockGraphqlOps({ + operations: getOperations({final: false, readOnly: false}) + }); + cy.visit('module/module-with-assignment'); + + cy.get('.submission-form__textarea').as('textarea'); + + cy.get('@textarea').invoke('val').should('contain', myText); + cy.get('@textarea').clear().type('Hello'); + cy.get('@textarea').should('not.have.attr', 'readonly'); + + cy.getByDataCy('submission-form-submit').should('exist'); + }); + + it('can not edit or turn in', () => { + cy.mockGraphqlOps({ + operations: getOperations({final: false, readOnly: true}) + }); + cy.visit('module/module-with-assignment'); + + cy.isSubmissionReadOnly(myText); + cy.canReopen(false); + }); + + it('can revoke turn in', () => { + cy.mockGraphqlOps({ + operations: getOperations({final: true, readOnly: false}) + }); + + cy.visit('module/module-with-assignment'); + cy.getByDataCy('final-submission').should('exist'); + cy.getByDataCy('final-submission-reopen').should('exist'); + }); + + it('can not revoke turn in', () => { + cy.mockGraphqlOps({ + operations: getOperations({final: true, readOnly: true}) + }); + + cy.visit('module/module-with-assignment'); + cy.getByDataCy('final-submission').should('exist'); + cy.canReopen(false); + }); +}); diff --git a/client/cypress/support/commands.js b/client/cypress/support/commands.js index 4c44718d..e2cb5bd8 100644 --- a/client/cypress/support/commands.js +++ b/client/cypress/support/commands.js @@ -35,16 +35,16 @@ Cypress.Commands.add('apolloLogin', (username, password) => { 'variables': { 'input': { 'usernameInput': username, - 'passwordInput': password - } + 'passwordInput': password, + }, }, - 'query': 'mutation BetaLogin($input: BetaLoginInput!) {\n betaLogin(input: $input) {\n success\n __typename\n }\n}\n' + 'query': 'mutation BetaLogin($input: BetaLoginInput!) {\n betaLogin(input: $input) {\n success\n __typename\n }\n}\n', }; cy.request({ method: 'POST', url: '/api/graphql-public/', - body: payload + body: payload, }); }); @@ -78,8 +78,8 @@ Cypress.Commands.add('loginByCsrf', (username, password, csrftoken) => { body: { username: username, password: password, - csrfmiddlewaretoken: csrftoken - } + csrfmiddlewaretoken: csrftoken, + }, }); }); @@ -189,3 +189,16 @@ Cypress.Commands.add('fakeLogin', () => { cy.log('Logging in (fake)'); cy.setCookie('loginStatus', 'true'); }); + +Cypress.Commands.add('canReopen', (exists) => { + let check = exists ? 'exist' : 'not.exist'; + cy.getByDataCy('final-submission-reopen').should(check); +}); + +Cypress.Commands.add('isSubmissionReadOnly', (myText) => { + cy.get('.submission-form__textarea--readonly').as('textarea'); + + cy.get('@textarea').invoke('val').should('contain', myText); + cy.get('@textarea').should('have.attr', 'readonly'); + cy.getByDataCy('submission-form-submit').should('not.exist'); +}); diff --git a/client/cypress/support/index.d.ts b/client/cypress/support/index.d.ts index 3dd7fd92..502c8c82 100644 --- a/client/cypress/support/index.d.ts +++ b/client/cypress/support/index.d.ts @@ -23,5 +23,9 @@ declare namespace Cypress { login(username: string, password: string, visitLogin?: boolean): void fakeLogin(username: string, password: string): void + + canReopen(exists: boolean): void + + isSubmissionReadOnly(myText: string): void } } diff --git a/client/src/components/content-blocks/assignment/Assignment.vue b/client/src/components/content-blocks/assignment/Assignment.vue index 87772616..7607b32d 100644 --- a/client/src/components/content-blocks/assignment/Assignment.vue +++ b/client/src/components/content-blocks/assignment/Assignment.vue @@ -16,6 +16,7 @@ :spellcheck-loading="spellcheckLoading" :saved="!unsaved" :spellcheck="true" + :read-only="me.readOnly" placeholder="Ergebnis erfassen" action="Ergebnis mit Lehrperson teilen" shared-msg="Das Ergebnis wurde mit der Lehrperson geteilt." diff --git a/client/src/components/content-blocks/assignment/FinalSubmission.vue b/client/src/components/content-blocks/assignment/FinalSubmission.vue index d2d8d55e..107a25a7 100644 --- a/client/src/components/content-blocks/assignment/FinalSubmission.vue +++ b/client/src/components/content-blocks/assignment/FinalSubmission.vue @@ -1,5 +1,7 @@