Skip to content

Commit

Permalink
Merge pull request #1837 from compdemocracy/te-cypress
Browse files Browse the repository at this point in the history
Improve cypress coverage
  • Loading branch information
tevko authored Nov 19, 2024
2 parents e961e77 + 38e1d8c commit 8704852
Show file tree
Hide file tree
Showing 14 changed files with 238 additions and 30 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ class Comment extends React.Component {

render() {
return (
<Card sx={{ mb: [3], minWidth: '35em' }}>
<Card sx={{ mb: [3], minWidth: '35em' }} data-test-id="pending-comment">
<Box>
<Text sx={{ mb: [3], color: 'red', fontSize: 12 }}>{this.props.comment.active ? null : 'Comment flagged as toxic by Jigsaw Perspective API. Comment not shown to participants. Accept to override.'}</Text>
<Text sx={{ mb: [3] }}>{this.props.comment.txt}</Text>
Expand All @@ -44,7 +44,7 @@ class Comment extends React.Component {
</Button>
) : null}
{this.props.rejectButton ? (
<Button onClick={this.onRejectClicked.bind(this)}>
<Button onClick={this.onRejectClicked.bind(this)} data-test-id="reject-comment">
{this.props.rejectButtonText}
</Button>
) : null}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ class CommentModeration extends React.Component {
</Heading>
<Flex sx={{ mb: [4] }}>
<Link
data-test-id="mod-queue"
sx={{
mr: [4],
variant: url ? 'links.nav' : 'links.activeNav'
Expand All @@ -80,6 +81,7 @@ class CommentModeration extends React.Component {
: null}
</Link>
<Link
data-test-id="filter-approved"
sx={{
mr: [4],
variant: url === 'accepted' ? 'links.activeNav' : 'links.nav'
Expand All @@ -91,6 +93,7 @@ class CommentModeration extends React.Component {
: null}
</Link>
<Link
data-test-id="filter-rejected"
sx={{
mr: [4],
variant: url === 'rejected' ? 'links.activeNav' : 'links.nav'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ class ModerateCommentsAccepted extends React.Component {

render() {
return (
<div>
<div data-test-id="approved-comments">
{this.props.accepted_comments !== null
? this.createCommentMarkup()
: 'Loading accepted comments...'}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ class ModerateCommentsRejected extends React.Component {

render() {
return (
<div>
<div data-test-id="rejected-comments">
{this.props.rejected_comments !== null
? this.createCommentMarkup()
: 'Loading rejected comments...'}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ class ModerateCommentsTodo extends React.Component {
render() {
const max = 100;
return (
<div>
<div data-test-id="pending-comment">
<div>
<p> Displays maximum {max} comments </p>
{this.props.unmoderated_comments !== null
Expand Down
1 change: 1 addition & 0 deletions client-admin/src/components/conversation-admin/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ class ConversationAdminContainer extends React.Component {
sx={{
variant: url === 'comments' ? 'links.activeNav' : 'links.nav'
}}
data-test-id="moderate-comments"
to={`${match.url}/comments`}>
Moderate
</Link>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import PropTypes from 'prop-types'
import Url from '../../../util/url'
import { connect } from 'react-redux'
import { Heading, Box, Button } from 'theme-ui'
import { populateZidMetadataStore } from '../../../actions'
import ComponentHelpers from '../../../util/component-helpers'
import NoPermission from '../no-permission'

Expand All @@ -31,11 +32,24 @@ class ReportsList extends React.Component {
})
})
}

componentDidMount() {
const { zid_metadata } = this.props

// eslint-disable-next-line react/prop-types
this.props.dispatch(
populateZidMetadataStore(this.props.match.params.conversation_id)
)

if (zid_metadata.is_mod) {
// If we already have is_mod, get the data
if (zid_metadata?.is_mod) {
this.getData()
}
}

componentDidUpdate() {
const { zid_metadata } = this.props
if (zid_metadata?.is_mod) {
this.getData()
}
}
Expand Down Expand Up @@ -75,7 +89,7 @@ class ReportsList extends React.Component {
</Box>
{this.state.reports.map((report) => {
return (
<Box sx={{ mb: [2] }} key={report.report_id}>
<Box sx={{ mb: [2] }} key={report.report_id} data-test-id="report-list-item">
<a
target="_blank"
rel="noreferrer"
Expand Down
15 changes: 13 additions & 2 deletions client-admin/src/components/conversation-admin/stats/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import dateSetupUtil from '../../../util/data-export-date-setup'
import React from 'react'
import { connect } from 'react-redux'
import { populateConversationStatsStore } from '../../../actions'
import { populateConversationStatsStore, populateZidMetadataStore } from '../../../actions'
import NumberCards from './conversation-stats-number-cards'
import Voters from './voters'
import Commenters from './commenters'
Expand Down Expand Up @@ -52,7 +52,11 @@ class ConversationStats extends React.Component {
}

componentDidMount() {
const { zid_metadata } = this.props
const { zid_metadata, match } = this.props

this.props.dispatch(
populateZidMetadataStore(match.params.conversation_id)
)

if (zid_metadata.is_mod) {
this.loadStats()
Expand All @@ -62,6 +66,13 @@ class ConversationStats extends React.Component {
}
}

componentDidUpdate() {
const { zid_metadata } = this.props
if (zid_metadata?.is_mod) {
this.loadStats()
}
}

componentWillUnmount() {
const { zid_metadata } = this.props

Expand Down
8 changes: 4 additions & 4 deletions client-report/src/components/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -447,29 +447,29 @@ class App extends React.Component {
render() {
if (this.state.error) {
return (
<div>
<div data-testid="reports-overview">
<div> Error Loading </div>
<div> {this.state.errorText} </div>
</div>
);
}
if (this.state.nothingToShow) {
return (
<div>
<div data-testid="reports-overview">
<div> Nothing to show yet </div>
</div>
);
}
if (this.state.loading) {
return (
<div>
<div data-testid="reports-overview">
<div> Loading ... </div>
</div>
);
}
console.log("top level app state and props", this.state, this.props);
return (
<div style={{ margin: "0px 10px" }}>
<div style={{ margin: "0px 10px" }} data-testid="reports-overview">
<Heading conversation={this.state.conversation} />
<div
style={{
Expand Down
53 changes: 53 additions & 0 deletions e2e/cypress/e2e/client-admin/comment-moderation.cy.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
describe('Comment Moderation', function () {
beforeEach(function () {
cy.intercept('GET', '/api/v3/conversations*').as('getConversations')
cy.intercept('GET', '/api/v3/comments*').as('getComments')
cy.intercept('POST', '/api/v3/comments').as('createComment')
cy.intercept('PUT', '/api/v3/comments*').as('updateComment')
cy.intercept('PUT', '/api/v3/mod/comments*').as('moderateComment')

// Create a conversation and add some comments
cy.createConvo().then(() => {
cy.visit('/m/' + this.convoId)
cy.wait('@getConversations')

// Set up initial comments
cy.get('textarea[data-test-id="seed_form"]').type('Initial comment for moderation')
cy.get('button').contains('Submit').click()
cy.wait('@createComment')
})
})

describe('Basic Moderation Actions', function () {
it('should reject an approved comment', function () {
cy.get('[data-test-id="moderate-comments"]').click()
cy.get('[data-test-id="filter-approved"]').click()
cy.get('[data-test-id="reject-comment"]').click()
cy.wait('@updateComment').then(({ response }) => {
expect(response.statusCode).to.equal(200)
})
cy.get('[data-test-id="pending-comment"]').should('not.exist')
cy.get('[data-test-id="filter-rejected"]').click()
cy.contains('button', 'accept').click()
cy.wait('@updateComment').then(({ response }) => {
expect(response.statusCode).to.equal(200)
})
})
})

describe('Moderation Settings', function () {
it('should filter comments by moderation status', function () {
cy.get('[data-test-id="moderate-comments"]').click()

// Test different filter options
cy.get('[data-test-id="filter-approved"]').click()
cy.get('[data-test-id="approved-comments"]').should('be.visible')

cy.get('[data-test-id="filter-rejected"]').click()
cy.get('[data-test-id="rejected-comments"]').should('exist')

cy.get('[data-test-id="mod-queue"]').click()
cy.get('[data-test-id="pending-comment"]').should('exist')
})
})
})
86 changes: 75 additions & 11 deletions e2e/cypress/e2e/client-admin/conversation.cy.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,29 +38,25 @@ describe('Conversation: Configure', function () {
cy.contains('button', 'Create new conversation').click()

cy.wait('@createConversation').then(({ response }) =>
cy.location('pathname').should('eq', '/m/' + response.body.conversation_id)
cy.location('pathname').should('eq', '/m/' + response.body.conversation_id),
)

cy.contains('h3', 'Configure').should('be.visible')

cy.get('input[data-test-id="topic"]')
.type('Test topic')
cy.get('input[data-test-id="topic"]').type('Test topic')

cy.get('input[data-test-id="topic"]')
.then(() => cy.focused().blur())
cy.get('input[data-test-id="topic"]').then(() => cy.focused().blur())

cy.wait('@updateConversation').then(({ response }) =>
expect(response.body.topic).to.equal('Test topic')
expect(response.body.topic).to.equal('Test topic'),
)

cy.get('textarea[data-test-id="description"]')
.type('Test description')
cy.get('textarea[data-test-id="description"]').type('Test description')

cy.get('textarea[data-test-id="description"]')
.then(() => cy.focused().blur())
cy.get('textarea[data-test-id="description"]').then(() => cy.focused().blur())

cy.wait('@updateConversation').then(({ response }) =>
expect(response.body.description).to.equal('Test description')
expect(response.body.description).to.equal('Test description'),
)

cy.get('textarea[data-test-id="seed_form"]').type('Test seed comment')
Expand All @@ -72,6 +68,74 @@ describe('Conversation: Configure', function () {
})
})

describe('Conversation Participation', function () {
beforeEach(function () {
cy.createConvo().then(() => {
cy.visit('/m/' + this.convoId)
cy.wait('@getConversations')
cy.get('input[data-test-id="topic"]').type('Participation Test Topic')
cy.get('textarea[data-test-id="description"]').type('Test description')
cy.get('textarea[data-test-id="seed_form"]').type('Initial seed comment')
cy.get('button').contains('Submit').click()
})
})

it('should allow multiple seed comments', function () {
cy.wait('@createComment', { timeout: 7000 })
cy.get('textarea[data-test-id="seed_form"]').clear()
cy.get('textarea[data-test-id="seed_form"]').type('Second seed comment')
// pause for 1 second to ensure the button is in correct state
cy.pause()

cy.get('button').contains('Submit').click()
cy.wait('@createComment', { timeout: 7000 })
cy.get('textarea[data-test-id="seed_form"]').clear()
cy.get('textarea[data-test-id="seed_form"]').type('third seed comment')
// pause for 1 second to ensure the button is in correct state
cy.pause()

cy.get('button').contains('Submit').click()
cy.wait('@createComment', { timeout: 7000 })

// Verify all seed comments are visible by checking API response
cy.request(`/api/v3/comments?conversation_id=${this.convoId}`).then((response) =>
expect(response.body.length).to.equal(3),
)
})

it('should handle special characters in topic and description', function () {
const specialTopic = 'Test & Topic with $pecial <characters>'
const specialDesc = '!@#$%^&*() Special description 你好'

cy.get('input[data-test-id="topic"]').clear().type(specialTopic)
cy.get('input[data-test-id="topic"]').then(() => cy.focused().blur())
cy.wait('@updateConversation')

cy.get('textarea[data-test-id="description"]').clear().type(specialDesc)
cy.get('textarea[data-test-id="description"]').then(() => cy.focused().blur())
cy.wait('@updateConversation')

// Verify the content is saved correctly
cy.reload()
cy.get('input[data-test-id="topic"]').should('have.value', specialTopic)
cy.get('textarea[data-test-id="description"]').should('have.value', specialDesc)
})
})

describe('Conversation Settings', function () {
beforeEach(function () {
cy.createConvo().then(() => cy.visit('/m/' + this.convoId))
cy.wait('@getConversations')
})

it('should toggle visibility settings correctly', function () {
cy.get('input[data-test-id="vis_type"]').check()
cy.wait('@updateConversation').then(({ response }) => {
expect(response.body.is_public).to.be.true
})
})
})

describe('Closing a Conversation', function () {
beforeEach(function () {
cy.createConvo().then(() => cy.visit('/m/' + this.convoId))
Expand Down
Loading

0 comments on commit 8704852

Please sign in to comment.