Move student view integration tests to new testing setup

Refs COMMS-2225

Test Plan:
  - Jenkins passes

Change-Id: I7481b0a2fa3ee1e2bf592a99e341543d04059a37
Reviewed-on: https://gerrit.instructure.com/201626
Tested-by: Jenkins
Reviewed-by: Steven Burnett <sburnett@instructure.com>
QA-Review: Landon Gilbert-Bland <lbland@instructure.com>
Product-Review: Landon Gilbert-Bland <lbland@instructure.com>
This commit is contained in:
Landon Gilbert-Bland 2019-07-17 13:57:37 -06:00
parent ee1fb516c1
commit c25ce6445c
5 changed files with 299 additions and 293 deletions

View File

@ -17,26 +17,45 @@
*/
import $ from 'jquery'
import * as uploadFileModule from '../../../shared/upload_file'
import {fireEvent, render, wait, waitForElement} from '@testing-library/react'
import {fireEvent, render, waitForElement} from '@testing-library/react'
import {CREATE_SUBMISSION_DRAFT} from '../graphqlData/Mutations'
import {createCache} from '../../../canvas-apollo'
import {MockedProvider} from 'react-apollo/test-utils'
import {mockQuery} from '../mocks'
import React from 'react'
import {singleAttachment, submissionGraphqlMock} from '../test-utils'
import {STUDENT_VIEW_QUERY} from '../graphqlData/Queries'
import {STUDENT_VIEW_QUERY, SUBMISSION_ID_QUERY} from '../graphqlData/Queries'
import SubmissionIDQuery from '../components/SubmissionIDQuery'
let mocks
async function createGraphqlMocks(overrides = {}) {
const mocks = [
{
query: SUBMISSION_ID_QUERY,
variables: {assignmentLid: '1'}
},
{
query: STUDENT_VIEW_QUERY,
variables: {assignmentLid: '1', submissionID: '1'}
},
{
query: CREATE_SUBMISSION_DRAFT,
variables: {id: '1', attempt: 0, fileIds: ['1']}
}
]
const mockResults = await Promise.all(
mocks.map(async ({query, variables}) => {
const result = await mockQuery(query, overrides, variables)
return {
request: {query, variables},
result
}
})
)
return mockResults
}
describe('SubmissionIDQuery', () => {
beforeAll(() => {
window.URL.createObjectURL = jest.fn()
uploadFileModule.uploadFiles = jest.fn()
$('body').append('<div role="alert" id="flash_screenreader_holder" />')
})
beforeEach(() => {
mocks = submissionGraphqlMock()
mocks[2].result.data.assignment.submissionsConnection.nodes[0].state = 'unsubmitted'
window.ENV = {
context_asset_string: 'test_1',
COURSE_ID: '1',
@ -45,18 +64,12 @@ describe('SubmissionIDQuery', () => {
}
})
const uploadFiles = (element, files) => {
fireEvent.change(element, {
target: {
files
}
})
}
// TODO: These three tests could be moved to the SubmissionIDQuery unit test file
it('renders normally', async () => {
const mocks = await createGraphqlMocks()
const {getByTestId} = render(
<MockedProvider mocks={mocks} removeTypename addTypename>
<SubmissionIDQuery assignmentLid="22" />
<MockedProvider mocks={mocks} cache={createCache()}>
<SubmissionIDQuery assignmentLid="1" />
</MockedProvider>
)
expect(
@ -65,155 +78,54 @@ describe('SubmissionIDQuery', () => {
})
it('renders loading', async () => {
const mocks = await createGraphqlMocks()
const {getByTitle} = render(
<MockedProvider mocks={mocks} removeTypename addTypename>
<SubmissionIDQuery assignmentLid="22" />
<MockedProvider mocks={mocks} cache={createCache()}>
<SubmissionIDQuery assignmentLid="1" />
</MockedProvider>
)
expect(getByTitle('Loading')).toBeInTheDocument()
})
// We have to do all these tests from this root component so that the apollo
// cache is actually populated for the components that are needed. Not ideal,
// maybe we could circle back later and find an easier way to handle these.
it('displays uploaded files', async () => {
uploadFileModule.uploadFiles.mockReturnValueOnce([{id: '1', name: 'file1.jpg'}])
const {container, getAllByText} = render(
<MockedProvider mocks={mocks} addTypename>
<SubmissionIDQuery assignmentLid="22" />
</MockedProvider>
)
const fileInput = await waitForElement(() =>
container.querySelector('input[id="inputFileDrop"]')
)
const file = new File(['foo'], 'file1.jpg', {type: 'image/jpg'})
uploadFiles(fileInput, [file])
expect(
await waitForElement(() => getAllByText(singleAttachment().displayName)[0])
).toBeInTheDocument()
})
it('notifies SR users when an attachment has been uploaded', async () => {
uploadFileModule.uploadFiles.mockReturnValueOnce([{id: '1', name: 'file1.jpg'}])
const {getByTestId, getByText} = render(
<MockedProvider mocks={mocks} addTypename>
<SubmissionIDQuery assignmentLid="22" />
</MockedProvider>
)
const fileInput = await waitForElement(() => getByTestId('input-file-drop'))
const file = new File(['foo'], 'file1.jpg', {type: 'image/jpg'})
uploadFiles(fileInput, [file])
await wait(() => {
expect(getByText('Submission draft updated')).toBeInTheDocument()
})
})
it('notifies users of error when attachments fail to upload in the API', async () => {
uploadFileModule.uploadFiles.mock.results = [
{type: 'throw', value: 'Error uploading file to Canvas API'}
]
const {getByTestId, getAllByText} = render(
<MockedProvider mocks={mocks} addTypename>
<SubmissionIDQuery assignmentLid="22" />
</MockedProvider>
)
const fileInput = await waitForElement(() => getByTestId('input-file-drop'))
const file = new File(['foo'], 'file1.jpg', {type: 'image/jpg'})
uploadFiles(fileInput, [file])
await wait(() => {
expect(getAllByText('Error updating submission draft')[0]).toBeInTheDocument()
})
})
it('notifies users of error when a submission fails to upload via graphql', async () => {
uploadFileModule.uploadFiles.mockReturnValueOnce([{id: '1', name: 'file1.jpg'}])
mocks[0].error = new Error('aw shucks')
const {getByTestId, getAllByText} = render(
<MockedProvider defaultOptions={{mutate: {errorPolicy: 'all'}}} mocks={mocks} addTypename>
<SubmissionIDQuery assignmentLid="22" />
</MockedProvider>
)
const fileInput = await waitForElement(() => getByTestId('input-file-drop'))
const file = new File(['foo'], 'file1.jpg', {type: 'image/jpg'})
uploadFiles(fileInput, [file])
await wait(() => {
expect(getAllByText('Error updating submission draft')[0]).toBeInTheDocument()
})
})
it('notifies SR users when a submission has been sent', async () => {
uploadFileModule.uploadFiles.mockReturnValueOnce([{id: '1', name: 'file1.jpg'}])
const {getByTestId, getByText} = render(
<MockedProvider mocks={mocks} addTypename>
<SubmissionIDQuery assignmentLid="22" />
</MockedProvider>
)
const fileInput = await waitForElement(() => getByTestId('input-file-drop'))
const file = new File(['foo'], 'file1.jpg', {type: 'image/jpg'})
uploadFiles(fileInput, [file])
const submitButton = await waitForElement(() => getByTestId('submit-button'))
fireEvent.click(submitButton)
await wait(() => {
expect(getByText('Submission sent')).toBeInTheDocument()
})
})
it('notifies users of error when a submission fails to send via graphql', async () => {
uploadFileModule.uploadFiles.mockReturnValueOnce([{id: '1', name: 'file1.jpg'}])
mocks[1].error = new Error('aw shucks')
const {getByTestId, getAllByText} = render(
<MockedProvider defaultOptions={{mutate: {errorPolicy: 'all'}}} mocks={mocks} addTypename>
<SubmissionIDQuery assignmentLid="22" />
</MockedProvider>
)
const fileInput = await waitForElement(() => getByTestId('input-file-drop'))
const file = new File(['foo'], 'file1.jpg', {type: 'image/jpg'})
uploadFiles(fileInput, [file])
const submitButton = await waitForElement(() => getByTestId('submit-button'))
fireEvent.click(submitButton)
await wait(() => {
expect(getAllByText('Error sending submission')[0]).toBeInTheDocument()
})
})
it('renders error', async () => {
const errorMock = [
{
request: {
query: STUDENT_VIEW_QUERY,
variables: {
assignmentLid: '7'
}
},
error: new Error('aw shucks')
}
]
const mocks = await createGraphqlMocks()
mocks[1].error = new Error('aw shucks')
const {getByText} = render(
<MockedProvider mocks={errorMock} removeTypename addTypename>
<SubmissionIDQuery assignmentLid="7" />
<MockedProvider mocks={mocks} cache={createCache()}>
<SubmissionIDQuery assignmentLid="1" />
</MockedProvider>
)
expect(await waitForElement(() => getByText('Sorry, Something Broke'))).toBeInTheDocument()
})
// This cannot be tested at the <AttemptTab> because the new file being
// displayed happens as a result of a cache write and these higher level
// components re-rendering
it('displays the new file after it has been uploaded', async () => {
window.URL.createObjectURL = jest.fn()
uploadFileModule.uploadFiles = jest.fn()
uploadFileModule.uploadFiles.mockReturnValueOnce([{id: '1', name: 'file1.jpg'}])
$('body').append('<div role="alert" id="flash_screenreader_holder" />')
const mocks = await createGraphqlMocks({
CreateSubmissionDraftPayload: () => ({
submissionDraft: () => ({attachments: [{displayName: 'test.jpg'}]})
})
})
const {container, getAllByText} = render(
<MockedProvider mocks={mocks} cache={createCache()}>
<SubmissionIDQuery assignmentLid="1" />
</MockedProvider>
)
const files = [new File(['foo'], 'file1.jpg', {type: 'image/jpg'})]
const fileInput = await waitForElement(() =>
container.querySelector('input[id="inputFileDrop"]')
)
fireEvent.change(fileInput, {target: {files}})
expect(await waitForElement(() => getAllByText('test.jpg')[0])).toBeInTheDocument()
})
})

View File

@ -55,7 +55,7 @@ export default class AttemptTab extends Component {
cache.writeQuery({
query: STUDENT_VIEW_QUERY,
variables: {assignmentLid: this.props.assignment._id},
variables: {assignmentLid: this.props.assignment._id, submissionID: this.props.submission.id},
data: {assignment}
})
}
@ -122,7 +122,7 @@ export default class AttemptTab extends Component {
if (this.state.submissionState === 'error') {
errorMessage = I18n.t('Error sending submission')
} else if (this.state.uploadState === 'success') {
} else if (this.state.submissionState === 'success') {
successMessage = I18n.t('Submission sent')
}

View File

@ -16,52 +16,72 @@
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import $ from 'jquery'
import * as uploadFileModule from '../../../../shared/upload_file'
import AttemptTab from '../AttemptTab'
import {mockAssignment, mockSubmission, submissionGraphqlMock} from '../../test-utils'
import {CREATE_SUBMISSION, CREATE_SUBMISSION_DRAFT} from '../../graphqlData/Mutations'
import {createCache} from '../../../../canvas-apollo'
import {fireEvent, render, wait, waitForElement} from '@testing-library/react'
import {mockAssignmentAndSubmission, mockQuery} from '../../mocks'
import {MockedProvider} from 'react-apollo/test-utils'
import React from 'react'
import {render} from '@testing-library/react'
import {STUDENT_VIEW_QUERY} from '../../graphqlData/Queries'
import {SubmissionMocks} from '../../graphqlData/Submission'
async function preloadCache() {
const variables = {assignmentLid: '1', submissionID: '1'}
const result = await mockQuery(STUDENT_VIEW_QUERY, {}, variables)
const cache = createCache()
cache.writeQuery({
query: STUDENT_VIEW_QUERY,
variables,
data: result.data
})
return cache
}
describe('ContentTabs', () => {
describe('the submission type is online_upload', () => {
const mockedAssignment = mockAssignment({
submissionTypes: ['online_upload']
})
it('renders the file upload tab when the submission is unsubmitted', () => {
const mockedSubmission = mockSubmission({
state: 'unsubmitted'
it('renders the file upload tab when the submission is unsubmitted', async () => {
const props = await mockAssignmentAndSubmission({
Assignment: () => ({submissionTypes: ['online_upload']})
})
const {getByTestId} = render(
<MockedProvider mocks={submissionGraphqlMock()} addTypename>
<AttemptTab assignment={mockedAssignment} submission={mockedSubmission} />
<MockedProvider>
<AttemptTab {...props} />
</MockedProvider>
)
expect(getByTestId('upload-pane')).toBeInTheDocument()
})
it('renders the file preview tab when the submission is submitted', () => {
it('renders the file preview tab when the submission is submitted', async () => {
const props = await mockAssignmentAndSubmission({
Assignment: () => ({submissionTypes: ['online_upload']}),
Submission: () => ({
...SubmissionMocks.submitted,
attachments: [{}]
})
})
const {getByTestId} = render(
<MockedProvider mocks={submissionGraphqlMock()} addTypename>
<AttemptTab assignment={mockedAssignment} submission={mockSubmission()} />
<MockedProvider>
<AttemptTab {...props} />
</MockedProvider>
)
expect(getByTestId('assignments_2_submission_preview')).toBeInTheDocument()
})
})
describe('the submission type is online_text_entry', () => {
const mockedAssignment = mockAssignment({
submissionTypes: ['online_text_entry']
})
it('renders the text entry tab', async () => {
const props = await mockAssignmentAndSubmission({
Assignment: () => ({submissionTypes: ['online_text_entry']})
})
it('renders the text entry tab', () => {
const {getByTestId} = render(
<MockedProvider mocks={submissionGraphqlMock()} addTypename>
<AttemptTab assignment={mockedAssignment} submission={mockSubmission()} />
<MockedProvider>
<AttemptTab {...props} />
</MockedProvider>
)
@ -69,3 +89,178 @@ describe('ContentTabs', () => {
})
})
})
describe('Submitting an assignment', () => {
beforeAll(() => {
$('body').append('<div role="alert" id="flash_screenreader_holder" />')
})
const createGraphqlMocks = async () => {
const variables = {
assignmentLid: '1',
fileIds: ['1'],
submissionID: '1',
type: 'online_upload'
}
const mockedResults = await mockQuery(CREATE_SUBMISSION, {}, variables)
return [
{
request: {
query: CREATE_SUBMISSION,
variables
},
result: mockedResults
}
]
}
it('notifies SR users when an assignment is submitted', async () => {
const mocks = await createGraphqlMocks()
const props = await mockAssignmentAndSubmission({
Submission: () => SubmissionMocks.draftWithAttachment,
File: () => ({_id: '1'})
})
const {getByTestId, getByText} = render(
<MockedProvider mocks={mocks} cache={createCache()}>
<AttemptTab {...props} />
</MockedProvider>
)
const submitButton = getByTestId('submit-button')
fireEvent.click(submitButton)
await wait(() => {
expect(getByText('Submission sent')).toBeInTheDocument()
})
})
it('shows an error when an assignment fails to be submitted', async () => {
const mocks = await createGraphqlMocks()
const props = await mockAssignmentAndSubmission({
Submission: () => SubmissionMocks.draftWithAttachment,
File: () => ({_id: '1'})
})
mocks[0].error = new Error('aw shucks')
const {getByTestId, getAllByText} = render(
<MockedProvider mocks={mocks} cache={createCache()}>
<AttemptTab {...props} />
</MockedProvider>
)
const submitButton = getByTestId('submit-button')
fireEvent.click(submitButton)
await wait(() => {
expect(getAllByText('Error sending submission')[0]).toBeInTheDocument()
})
})
})
describe('Uploading a file', () => {
beforeAll(() => {
$('body').append('<div role="alert" id="flash_screenreader_holder" />')
uploadFileModule.uploadFiles = jest.fn()
window.URL.createObjectURL = jest.fn()
})
const uploadFiles = (element, files) => {
fireEvent.change(element, {
target: {
files
}
})
}
const createGraphqlMocks = async () => {
const variables = {id: '1', attempt: 0, fileIds: ['1']}
const mockedResults = await mockQuery(CREATE_SUBMISSION_DRAFT, {}, variables)
return [
{
request: {
query: CREATE_SUBMISSION_DRAFT,
variables
},
result: mockedResults
}
]
}
it('shows an error when creating a new SubmissionDraft fails', async () => {
const props = await mockAssignmentAndSubmission()
const mocks = await createGraphqlMocks()
mocks[0].error = new Error('aw shucks')
uploadFileModule.uploadFiles.mockReturnValueOnce([{id: '1', name: 'file1.jpg'}])
const {getByTestId, getAllByText} = render(
<MockedProvider mocks={mocks} cache={createCache()}>
<AttemptTab {...props} />
</MockedProvider>
)
const fileInput = getByTestId('input-file-drop')
const file = new File(['foo'], 'file1.jpg', {type: 'image/jpg'})
uploadFiles(fileInput, [file])
await wait(() => {
expect(getAllByText('Error updating submission draft')[0]).toBeInTheDocument()
})
})
it('shows an error when uploading a file fails', async () => {
const props = await mockAssignmentAndSubmission()
const mocks = await createGraphqlMocks()
uploadFileModule.uploadFiles.mock.results = [
{type: 'throw', value: 'Error uploading file to Canvas API'}
]
const {getByTestId, getAllByText} = render(
<MockedProvider mocks={mocks} cache={createCache()}>
<AttemptTab {...props} />
</MockedProvider>
)
const fileInput = getByTestId('input-file-drop')
const file = new File(['foo'], 'file1.jpg', {type: 'image/jpg'})
uploadFiles(fileInput, [file])
await wait(() => {
expect(getAllByText('Error updating submission draft')[0]).toBeInTheDocument()
})
})
it('notifies SR users when a submission draft has been saved', async () => {
const cache = await preloadCache()
const props = await mockAssignmentAndSubmission()
const mocks = await createGraphqlMocks()
uploadFileModule.uploadFiles.mockReturnValueOnce([{id: '1', name: 'file1.jpg'}])
const {getByTestId, getByText} = render(
<MockedProvider mocks={mocks} cache={cache}>
<AttemptTab {...props} />
</MockedProvider>
)
const fileInput = getByTestId('input-file-drop')
const file = new File(['foo'], 'file1.jpg', {type: 'image/jpg'})
uploadFiles(fileInput, [file])
await wait(() => {
expect(getByText('Submission draft updated')).toBeInTheDocument()
})
})
it('shows a file preview for an uploaded file', async () => {
const props = await mockAssignmentAndSubmission({
Submission: () => ({
submissionDraft: {
attachments: [{displayName: 'test.jpg'}]
}
})
})
const {getAllByText} = render(
<MockedProvider cache={createCache()}>
<AttemptTab {...props} />
</MockedProvider>
)
expect(await waitForElement(() => getAllByText('test.jpg')[0])).toBeInTheDocument()
})
})

View File

@ -15,16 +15,8 @@
* You should have received a copy of the GNU Affero General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import {
STUDENT_VIEW_QUERY,
SUBMISSION_COMMENT_QUERY,
SUBMISSION_ID_QUERY
} from './graphqlData/Queries'
import {
CREATE_SUBMISSION,
CREATE_SUBMISSION_COMMENT,
CREATE_SUBMISSION_DRAFT
} from './graphqlData/Mutations'
import {CREATE_SUBMISSION_COMMENT} from './graphqlData/Mutations'
import {SUBMISSION_COMMENT_QUERY} from './graphqlData/Queries'
export function mockAssignment(overrides = {}) {
return {
@ -278,102 +270,6 @@ export function mockGraphqlQueryResults(overrides = {}) {
return assignment
}
export function submissionGraphqlMock() {
return [
{
request: {
query: CREATE_SUBMISSION_DRAFT,
variables: {
id: mockSubmission().id,
attempt: 1,
fileIds: ['1']
}
},
result: {
data: {
createSubmissionDraft: {
submissionDraft: {
__typename: 'SubmissionDraft',
_id: '22',
attachments: [singleAttachment({_id: '1'})]
},
errors: {
attribute: null,
message: null,
__typename: 'Errors'
},
__typename: 'CreateSubmissionDraftPayload'
}
}
}
},
{
request: {
query: CREATE_SUBMISSION,
variables: {
assignmentLid: '22',
submissionID: mockSubmission().id,
type: 'online_upload',
fileIds: ['1']
}
},
result: {
data: {
createSubmission: {
submission: mockSubmission(),
errors: {
attribute: null,
message: null,
__typename: 'Errors'
},
__typename: 'CreateSubmissionPayload'
}
}
}
},
{
request: {
query: STUDENT_VIEW_QUERY,
variables: {
assignmentLid: '22',
submissionID: mockSubmission().id
}
},
result: {
data: {
assignment: mockGraphqlQueryResults({
lockInfo: {isLocked: false, __typename: 'LockInfo'}
})
}
}
},
{
request: {
query: SUBMISSION_ID_QUERY,
variables: {
assignmentLid: '22'
}
},
result: {
data: {
assignment: {
submissionsConnection: {
nodes: [
{
id: mockSubmission().id,
__typename: 'Submission'
}
],
__typename: 'SubmissionConnection'
},
__typename: 'Assignment'
}
}
}
}
]
}
export function mockSubmission(overrides = {}) {
return {
attachments: mockMultipleAttachments(),

View File

@ -57,15 +57,18 @@ function createHttpLink() {
})
}
function createClient(opts = {}) {
const cache = new InMemoryCache({
function createCache() {
return new InMemoryCache({
addTypename: true,
dataIdFromObject: object => object.id || null,
fragmentMatcher: new IntrospectionFragmentMatcher({
introspectionQueryResultData
})
})
}
function createClient(opts = {}) {
const cache = createCache()
const defaults = opts.defaults || {}
const resolvers = opts.resolvers || {}
const stateLink = withClientState({
@ -87,4 +90,4 @@ function createClient(opts = {}) {
return client
}
export {createClient, gql, ApolloProvider, Query}
export {createClient, gql, ApolloProvider, Query, createCache}