Skip to content

Commit

Permalink
Merge pull request #112 from OxfordRSE/test-delete-event
Browse files Browse the repository at this point in the history
Add e2e for create/delete event and adds paragraph component tests
  • Loading branch information
martinjrobins authored Nov 30, 2023
2 parents cb2bf3a + 8235ee0 commit 2030a6d
Show file tree
Hide file tree
Showing 10 changed files with 334 additions and 8 deletions.
4 changes: 3 additions & 1 deletion .env
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,6 @@ GITHUB_ID="github_id"
DATABASE_URL=postgres://user:password@localhost:5432
QDRANT_COLLECTION_NAME="gutenberg"
QDRANT_API_KEY=""
QDRANT_DB_URL="http://qdrant-database.fly.dev:6333"
QDRANT_DB_URL="http://qdrant-database.fly.dev:6333"
ELECTRON_ENABLE_LOGGING=true
DEBUG=cypress:server:browsers:electron
4 changes: 2 additions & 2 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,9 @@ jobs:
DATABASE_URL: postgresql://postgres:postgres@localhost:5432/gutenberg
steps:
- name: Checkout
uses: actions/checkout@v3
uses: actions/checkout@v4
- name: Checkout material repo
uses: actions/checkout@v3
uses: actions/checkout@v4
with:
repository: ${{ env.MATERIAL_REPO }}
path: .material
Expand Down
1 change: 1 addition & 0 deletions components/EventsView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ const EventsView: React.FC<EventsProps> = ({ material, events }) => {
<Timeline.Time className='flex justify-between'>
<Link href={`/event/${event.id}`}>{showDateTime && event.start.toLocaleString([], { dateStyle: 'medium', timeStyle: 'short'})}</Link>
{ isAdmin && (<MdDelete className="ml-2 inline text-red-500 flex cursor-pointer"
data-cy={`delete-event-${event.id}`}
size={18} onClick={() => openDeleteEventModal(event.id)} />)}
</Timeline.Time>
<Timeline.Title>
Expand Down
2 changes: 1 addition & 1 deletion components/content/Comment.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ const CommentView = ({ comment, mutateComment, deleteComment, isPlaceholder, sav
}

return (
<form>
<form data-cy="new-comment-form">
<div className="mx-1 p-1 border border-gray-200 rounded-lg bg-slate-100 dark:bg-slate-800 dark:border-gray-700 mb-4" data-cy={`Comment:${comment.id}:Main`}>
{ (editing && hasEditPermission) ? (
<div data-cy={`Comment:${comment.id}:Editing`}>
Expand Down
3 changes: 2 additions & 1 deletion components/content/Paragraph.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ const Paragraph: React.FC<ParagraphProps> = ({ content, section }) => {

const similarThreads = commentThreads?.filter((thread) => section === thread.section)
.filter((thread) => {

const threadTokens = nlp.readDoc( thread.textRef )
.tokens()
.filter(
Expand Down Expand Up @@ -136,7 +137,7 @@ const Paragraph: React.FC<ParagraphProps> = ({ content, section }) => {

return (
<>
<div ref={ref} className="relative">
<div data-cy="paragraph" ref={ref} className="relative">
{content}
{ activeEvent && (
<div className={`absolute top-0 right-0 md:-right-6 xl:-right-[420px]`}>
Expand Down
1 change: 1 addition & 0 deletions components/content/Popover.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ const Popover = ({ target, onCreate }: { target?: HTMLElement, onCreate: (text:
return (
<Portal>
<Button
data-cy="new-comment-button"
style={{
left: clientRect.x + clientRect.width / 2 - 25,
top: clientRect.y - 50 + window.scrollY,
Expand Down
5 changes: 3 additions & 2 deletions components/deleteEventModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -102,11 +102,12 @@ export const DeleteEventModal: React.FC<DeleteEventProps> = ({onClose}) => {
<Button className="mt-4"
color="failure"
onClick={handleDeleteEvent}
disabled={buttonDisabled}>
disabled={buttonDisabled}
data-cy="confirm-event-delete">
Delete Event
</Button>
{ success && (
<Toast className=''>
<Toast data-cy="event-deleted-toast" className=''>
<div className="inline-flex h-8 w-8 shrink-0 items-center justify-center rounded-lg bg-green-100 text-green-500 dark:bg-green-800 dark:text-green-200">
<HiCheckCircle className="h-5 w-5" />
</div>
Expand Down
248 changes: 248 additions & 0 deletions cypress/component/Paragraph.cy.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,248 @@
import Paragraph from "components/content/Paragraph";
import { Section } from "lib/material";
import { Event } from 'pages/api/event/[eventId]'
import { User } from 'pages/api/user/[email]';
import { CommentThread } from "pages/api/commentThread";
import { threadId } from "worker_threads";


describe("Paragraph", () => {
const threadId = 1;
const threads: CommentThread[] = [{
id: 1,
eventId: 1,
groupId: null,
section: 'test-comment',
problemTag: '',
textRef: 'paragraph test comment',
textRefStart: -1,
textRefEnd: 5,
createdByEmail: "[email protected]",
created: new Date(),
resolved: false,
instructorOnly: false,
Comment: [
{
id: 1,
threadId: threadId,
createdByEmail: "[email protected]",
created: new Date(),
index: 0,
markdown: 'This is a test comment that should appear',
}
],
},
{
id: 2,
eventId: 1,
groupId: null,
section: 'test-comment',
problemTag: '',
textRef: 'this textref does not exist anywhere in the dom',
textRefStart: -1,
textRefEnd: 5,
createdByEmail: "[email protected]",
created: new Date(),
resolved: false,
instructorOnly: false,
Comment: [
{
id: 1,
threadId: threadId,
createdByEmail: "[email protected]",
created: new Date(),
index: 0,
markdown: 'paragraph test comment',
}
],
},
{
id: 3,
eventId: 1,
groupId: null,
section: 'this-section-does-not-exist',
problemTag: '',
textRef: 'this textref does not exist anywhere in the dom',
textRefStart: -1,
textRefEnd: 5,
createdByEmail: "[email protected]",
created: new Date(),
resolved: false,
instructorOnly: false,
Comment: [
{
id: 1,
threadId: threadId,
createdByEmail: "[email protected]",
created: new Date(),
index: 0,
markdown: 'This is a test comment that should never appear',
}
],
}]
const section: Section = {
id: '1',
file: 'test.md',
course: 'test course',
theme: 'test theme',
name: 'test name',
markdown: 'example \n markdown \n',
dependsOn: [],
tags: ['tag'],
index: 1,
type: '',
attribution: [{
citation: 'author',
url: 'test',
image: 'test',
license: 'test',
}],
problems: ['problem1'],
}
const currentUser: User = {
id: '2',
email: "[email protected]",
name: 'Test User',
image: 'https://www.example.com/image.png',
admin: false,
emailVerified: new Date(),
};
const event: Event = {
content: 'test',
end: new Date(),
start: new Date(),
id: 1,
enrol: '',
enrolKey: 'test',
instructorKey: 'instructortest',
name: 'test',
EventGroup: [],
hidden: false,
summary: '',
UserOnEvent: [
{
eventId: 1,
status: 'STUDENT',
userEmail: "[email protected]",
user: currentUser,
},
],
};
beforeEach(() => {
cy.intercept(`/api/user/[email protected]`, { user: currentUser }).as("currentUser");
cy.intercept(`/api/commentThread`, { commentThreads: threads }).as("commentThreads");
cy.intercept(`/api/commentThread?eventId=1`, { commentThreads: threads }).as("commentThreads");
cy.intercept(`/api/commentThread/1`, { commentThread: threads[0] }).as("commentThread");
cy.intercept(`/api/event/1`, { event }).as("event");
})
it("renders", () => {
cy.mount(<div className="mt-4 pt-4">
<div className="mt-4 pt-4">
<Paragraph section={"test"} content={"Paragraph test"}/>
</div>
</div>)
});
context('without active event', () => {
it("comment should not exist despite match", () => {
cy.mount(<div className="mt-4 pt-4">
<div className="mt-4 pt-4">
<Paragraph section={"test-comment"} content={"paragraph test comment"}/>
</div>
</div>)
cy.get('[data-cy="paragraph"]').should('exist')
cy.get('[data-cy="Thread:1:OpenCloseButton"]').should('not.exist')
})
it("comment should not exist", () => {
cy.mount(<div className="mt-4 pt-4">
<div className="mt-4 pt-4">
<Paragraph section={"test-comment"} content={"paragraph test comment"}/>
</div>
</div>)
cy.get('[data-cy="paragraph"]').should('exist')
cy.get('[data-cy="Thread:2:OpenCloseButton"]').should('not.exist')
})
})

context('with active event', () => {
beforeEach(() => {
cy.stub(localStorage, 'getItem').returns('1');
})
it("comment exists and matches", () => {
cy.mount(<div className="mt-4 pt-4">
<div className="mt-4 pt-4">
<Paragraph section={"test-comment"} content={"paragraph test comment"}/>
</div>
</div>)
cy.get('[data-cy="paragraph"]').should('exist')
cy.get('[data-cy="Thread:1:OpenCloseButton"]').should('exist')
})
it("comment opened", () => {
cy.on('uncaught:exception', (err, runnable) => {
// returning false here prevents Cypress from
// failing the test TODO: we need to revisit this at some point
return false
})
cy.mount(<div className="mt-4 pt-4">
<div className="mt-4 pt-4">
<Paragraph section={"test-comment"} content={"paragraph test comment"}/>
</div>
</div>)
cy.get('[data-cy="Thread:1:Dropdown"]').should('not.exist')
cy.get('[data-cy="Thread:1:OpenCloseButton"]').click().wait(100).get('[data-cy="Thread:1:Dropdown"]').should('exist')
})
it("comment does not match textref", () => {
cy.mount(<div className="mt-4 pt-4">
<div className="mt-4 pt-4">
<Paragraph section={"test-comment"} content={"paragraph test comment"}/>
</div>
</div>)
cy.get('[data-cy="paragraph"]').should('exist')
cy.get('[data-cy="Thread:2:OpenCloseButton"]').should('not.exist')
})
it("comment does not match", () => {
cy.mount(<div className="mt-4 pt-4">
<div className="mt-4 pt-4">
<Paragraph section={"test-comment"} content={"paragraph test without comment"}/>
</div>
</div>)
cy.get('[data-cy="paragraph"]').should('exist')
cy.get('[data-cy="Thread:1:OpenCloseButton"]').should('not.exist')
})
it("comment does not match section", () => {
cy.mount(<div className="mt-4 pt-4">
<div className="mt-4 pt-4">
<Paragraph section={"test-comment"} content={"paragraph test comment"}/>
</div>
</div>)
cy.get('[data-cy="paragraph"]').should('exist')
cy.get('[data-cy="Thread:3:OpenCloseButton"]').should('not.exist')
})


it("new comment button", () => {
cy.mount(<div className="mt-4 pt-4">
<div className="mt-4 pt-4">
<Paragraph section={"test"} content={"Paragraph test"}/>
</div>
</div>)
cy.get('[data-cy="new-comment-button"]').should('not.exist')
cy.get('[data-cy="paragraph"]')
.trigger('mousedown', { which: 1, x: 10, y: 10 })
.wait(100)
.then(($el) => {
const el = $el[0]
const document = el.ownerDocument
const range = document.createRange()
range.selectNodeContents(el)
document.getSelection()?.removeAllRanges()
document.getSelection()?.addRange(range)
})
.trigger('mouseup', { which: 1, x: 70, y: 10 })
cy.document().trigger('selectionchange')
cy.get('[data-cy="new-comment-button"]').should('be.visible')
cy.get('[data-cy="new-comment-form"]').should('not.exist')
cy.get('[data-cy="new-comment-button"]').click()
cy.get('[data-cy="new-comment-form"]').should('be.visible')
});
})
})
65 changes: 65 additions & 0 deletions cypress/e2e/landing-page-admin.cy.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
describe('admin landing page', () => {

const user = {
name: "admin",
email: "admin@localhost",
};

beforeEach(() => {
cy.visit('/')
cy.login(user)
cy.visit('/')
})

it('Create event button exists', () => {
cy.contains('Create new Event').should('be.visible')
})

it('Delete event button exists', () => {
cy.get('[data-cy*="delete-event"]').should('be.visible')
})

it('admin create/delete event', () => {
cy.intercept('GET', '/api/auth/session').as('getSession')

cy.request('GET', '/api/event')
.its('body')
.its('events')
.as('oldres')
cy.contains('Create new Event').click()

cy.wait(1000).request('GET', '/api/event')
.its('body')
.its('events')
.as('newres')

cy.get('@oldres').then((oldres) => {
cy.get('@newres').then((newres) => {
// Verify that the second event response has one more item than the first one
expect(newres.length).to.eq(oldres.length + 1)
cy.wait(1000).then(() => {
let deleteId = 0
newres.map(item => {
if (item.id > deleteId) {
deleteId = item.id
}
})
cy.get('[data-cy="delete-event-'+deleteId+'"]').click()
cy.get('[data-cy="confirm-event-delete"]').should('be.visible')
cy.wait(2100).get('[data-cy="confirm-event-delete"]').click()
cy.get('[data-cy="event-deleted-toast"]').should('be.visible')
cy.wait(500).request('GET', '/api/event/')
.its('body')
.its('events')
.as('afterdeleteres')
cy.get('@afterdeleteres').then((res) => {
// have deleted last added event
expect(res.length).to.eq(oldres.length)
})
})
});
});


})
})
Loading

0 comments on commit 2030a6d

Please sign in to comment.