Skip to content
This repository has been archived by the owner on Feb 22, 2023. It is now read-only.

Media reporting e2e tests, single audio support, style updates, and accessibility improvements #1276

Merged
merged 12 commits into from Apr 16, 2022
10 changes: 7 additions & 3 deletions src/components/VAudioDetails/VAudioDetails.vue
@@ -1,8 +1,12 @@
<template>
<section class="audio-info">
<h4 class="text-base lg:text-3xl mb-6">
{{ $t('audio-details.information') }}
</h4>
<header class="flex flex-row justify-between items-center mb-6">
<h4 class="text-base lg:text-3xl">
{{ $t('audio-details.information') }}
</h4>
<VContentReportPopover :media="audio" />
</header>
Comment on lines +3 to +8
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This adds the report form and button to the single audio results.


<div class="flex flex-col md:flex-row items-start gap-6">
<div class="w-[75px] h-[75px] lg:w-30 lg:h-30 rounded-sm overflow-hidden">
<VAudioThumbnail :audio="audio" />
Expand Down
6 changes: 3 additions & 3 deletions src/components/VContentReport/VContentReportButton.vue
@@ -1,12 +1,12 @@
<template>
<VButton
variant="plain"
class="report-button font-semibold text-dark-charcoal"
class="report-button font-semibold text-dark-charcoal-70"
>
<span class="md:hidden">{{
<span class="text-sr md:text-base md:hidden">{{
$t('media-details.content-report.short')
}}</span>
<span class="hidden md:inline">{{
<span class="text-sr md:text-base hidden md:inline">{{
Comment on lines +4 to +9
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Style updates to the reporting button so it matches the mockups:

CleanShot 2022-04-14 at 16 16 24@2x

$t('media-details.content-report.long')
}}</span>
<VIcon :icon-path="icons.flag" class="ms-2" />
Expand Down
9 changes: 6 additions & 3 deletions src/components/VContentReport/VContentReportForm.vue
Expand Up @@ -40,7 +40,7 @@
}}
</p>

<form class="text-sm">
<form class="text-sm" @submit="handleSubmit">
<fieldset class="flex flex-col">
<legend class="font-semibold mb-4">
{{ $t('media-details.content-report.form.question') }}
Expand Down Expand Up @@ -93,10 +93,11 @@
<VButton
v-else
key="non-dmca"
type="submit"
:disabled="isSubmitDisabled"
:focusable-when-disabled="true"
variant="secondary"
@click="handleSubmit"
:value="$t('media-details.content-report.form.submit')"
Copy link
Member Author

@zackkrida zackkrida Apr 14, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fun fact: Playwright's selectors for text (page.locate('text="Submit"'), for example) use the value attribute when applied to submit buttons, not the actual button text contents.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TIL! I guess we should add value attribute to all the submit buttons? I wonder if it uses value for all buttons...

>
{{ $t('media-details.content-report.form.submit') }}
</VButton>
Expand Down Expand Up @@ -166,11 +167,13 @@ export default defineComponent({
const isSubmitDisabled = computed(
() => selectedReason.value === OTHER && description.value.length < 20
)
const handleSubmit = async () => {
const handleSubmit = async (event) => {
event.preventDefault()
Copy link
Member Author

@zackkrida zackkrida Apr 14, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

      event.preventDefault()

Prevents redirection to the api POST request endpoint.

if (selectedReason.value === DMCA) return
// Submit report
try {
await service.sendReport({
mediaType: props.media.frontendMediaType,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I keep forgetting that we can use the frontendMediaType property!

identifier: props.media.id,
reason: selectedReason.value,
description: description.value,
Expand Down
4 changes: 2 additions & 2 deletions src/data/report-service.ts
@@ -1,4 +1,4 @@
import { IMAGE, MediaType } from '~/constants/media'
import type { MediaType } from '~/constants/media'
import type { ReportReason } from '~/constants/content-report'
import { getResourceSlug, VersionedApiService } from '~/data/api-service'

Expand All @@ -10,7 +10,7 @@ interface ReportParams {
}
const ReportService = {
sendReport(params: ReportParams) {
const mediaType = params.mediaType ?? IMAGE
const mediaType = params.mediaType
return VersionedApiService.post(
`/${getResourceSlug(mediaType)}${params.identifier}/report`,
params
Expand Down
20 changes: 10 additions & 10 deletions src/locales/po-files/openverse.pot
Expand Up @@ -4,7 +4,7 @@ msgid ""
msgstr ""
"Project-Id-Version: Openverse \n"
"Report-Msgid-Bugs-To: https://github.com/wordpress/openverse/issues \n"
"POT-Creation-Date: 2022-04-14T15:48:23+00:00\n"
"POT-Creation-Date: 2022-04-14T20:30:51+00:00\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
Expand Down Expand Up @@ -324,42 +324,42 @@ msgctxt "audio-details.related-audios"
msgid "Related audio"
msgstr ""

#: src/components/VAudioDetails/VAudioDetails.vue:4
#: src/components/VAudioDetails/VAudioDetails.vue:5
msgctxt "audio-details.information"
msgid "Audio information"
msgstr ""

#: src/components/VAudioDetails/VAudioDetails.vue:23
#: src/components/VAudioDetails/VAudioDetails.vue:27
msgctxt "audio-details.table.album"
msgid "Album"
msgstr ""

#: src/components/VAudioDetails/VAudioDetails.vue:31
#: src/components/VAudioDetails/VAudioDetails.vue:35
msgctxt "audio-details.table.category"
msgid "Type"
msgstr ""

#: src/components/VAudioDetails/VAudioDetails.vue:38
#: src/components/VAudioDetails/VAudioDetails.vue:42
msgctxt "audio-details.table.sample-rate"
msgid "Sample Rate"
msgstr ""

#: src/components/VAudioDetails/VAudioDetails.vue:46
#: src/components/VAudioDetails/VAudioDetails.vue:50
msgctxt "audio-details.table.filetype"
msgid "Format"
msgstr ""

#: src/components/VAudioDetails/VAudioDetails.vue:54
#: src/components/VAudioDetails/VAudioDetails.vue:58
msgctxt "audio-details.table.provider"
msgid "Provider"
msgstr ""

#: src/components/VAudioDetails/VAudioDetails.vue:64
#: src/components/VAudioDetails/VAudioDetails.vue:68
msgctxt "audio-details.table.source"
msgid "Source"
msgstr ""

#: src/components/VAudioDetails/VAudioDetails.vue:72
#: src/components/VAudioDetails/VAudioDetails.vue:76
msgctxt "audio-details.table.genre"
msgid "Genre"
msgstr ""
Expand Down Expand Up @@ -492,7 +492,7 @@ msgctxt "media-details.content-report.form.question"
msgid "What is the reason?"
msgstr ""

#: src/components/VContentReport/VContentReportForm.vue:101
#: src/components/VContentReport/VContentReportForm.vue:100
msgctxt "media-details.content-report.form.submit"
msgid "Report"
msgstr ""
Expand Down
109 changes: 109 additions & 0 deletions test/playwright/e2e/report-media.spec.ts
@@ -0,0 +1,109 @@
import { test, expect, Page, BrowserContext } from '@playwright/test'

import { mockProviderApis } from '~~/test/playwright/utils/route'

/**
* Some helpers for repeated actions.
*/

const reportingEndpoint = '**/report/'

export const visitFirstResult = (page: Page) =>
page.click('[data-testid="search-results"] a:first-child')
export const openReportModal = (page: Page) =>
page.click('text="Report this content"')

// Mock a successful reporting response
export const mockReportingEndpoint = (context: BrowserContext) =>
context.route(reportingEndpoint, (route) => {
route.fulfill({
status: 200,
contentType: 'text/json',
headers: { 'access-control-allow-origin': '*' },
})
})

// Submit the content form and return the network response
export const submitApiReport = (page: Page) =>
Promise.all([
page.waitForResponse(reportingEndpoint),
page.locator('button[type="submit"]:has-text("Report")').click(),
]).then((res) => res[0])

/**
* Reports
*/

const submitDmcaReport = async (page: Page, context: BrowserContext) => {
// Mock the Google Form to return a successful html document
await context.route('https://docs.google.com/forms/**', (route) => {
route.fulfill({
status: 200,
contentType: 'text/html',
body: '<div>Fake form!</div>',
})
})
await page.click('text="Infringes copyright"')
const [newPage] = await Promise.all([
context.waitForEvent('page'),
await page.click('text="Open form"'), // Opens a new tab
])
await newPage.waitForLoadState()
return expect(await newPage.url()).toContain('https://docs.google.com/forms')
}

// todo: Test a mature report with the optional description field
const submitMatureContentReport = async (
page: Page,
context: BrowserContext
) => {
await mockReportingEndpoint(context)
await page.click('text="Contains mature content"')
const response = await submitApiReport(page)
return expect(response.status()).toBe(200)
}

const submitOtherReport = async (page: Page, context: BrowserContext) => {
await mockReportingEndpoint(context)
await page.click('text="Other"')
await page.fill(
'text=Describe the issue',
'This is an example "Other" report submit by Playwright, our automated e2e test tool.'
)
const response = await submitApiReport(page)
return expect(response.status()).toBe(200)
}

test.beforeEach(async ({ context }) => {
await mockProviderApis(context)
})

const mediaTypes = ['Images', 'Audio']
const reports = {
dmca: submitDmcaReport,
mature: submitMatureContentReport,
other: submitOtherReport,
}

/**
* Iterate through all the media types and supported reports
* to make sure every permutation works correctly.
*/
mediaTypes.forEach((mediaType) => {
Object.entries(reports).forEach(([reportName, reportAssertion]) => {
test(`Files ${reportName} report for ${mediaType.toLowerCase()}`, async ({
page,
context,
}) => {
await page.goto('/')
await page.click(`[aria-label="All content"]`)
await page.click(`button[role="radio"]:has-text("${mediaType}")`)
const searchInput = page.locator('main input[type="search"]')
await searchInput.type('cat')
await page.click('[aria-label="Search"]')
await visitFirstResult(page)
await openReportModal(page)
await reportAssertion(page, context)
})
})
})
3 changes: 3 additions & 0 deletions test/unit/specs/components/v-content-report-form.spec.js
Expand Up @@ -55,6 +55,7 @@ describe('VContentReportForm', () => {
id: '0aff3595-8168-440b-83ff-7a80b65dea42',
foreign_landing_url: 'https://wordpress.org/openverse/',
provider: 'provider',
frontendMediaType: 'image',
},
providerName: 'Provider',
closeFn: jest.fn(),
Expand Down Expand Up @@ -127,6 +128,7 @@ describe('VContentReportForm', () => {
expect(serviceMock.sendReport).toHaveBeenCalledWith({
identifier: props.media.id,
reason: 'mature',
mediaType: props.media.frontendMediaType,
description: '',
})
})
Expand All @@ -145,6 +147,7 @@ describe('VContentReportForm', () => {
expect(serviceMock.sendReport).toHaveBeenCalledWith({
identifier: props.media.id,
reason: 'other',
mediaType: 'image',
description,
})
})
Expand Down