diff --git a/src/apps/opportunities/README.md b/src/apps/opportunities/README.md index 4b25c7221..e04f02be2 100644 --- a/src/apps/opportunities/README.md +++ b/src/apps/opportunities/README.md @@ -695,8 +695,11 @@ challenge track, while authored external-URL rows omit that file action. The browser requests a short-lived URL from `GET /v6/submissions/:submissionId/download-url` instead of using submission list URLs; Review API remains authoritative for access and signs only clean -storage, so pending DMZ and quarantined files cannot be downloaded. Work -Manager's case-insensitive `submission_type=url` challenge +storage, so pending DMZ and quarantined files cannot be downloaded. TopGear +challenges use the URL experience whenever the app is served on the TopGear host +or the challenge belongs to the configured TopGear group, including when opened +through `?tab=mine`. This takes precedence over missing or ZIP submission metadata. +For other challenges, Work Manager's case-insensitive `submission_type=url` metadata selects the URL experience; every other value, including missing or malformed metadata, retains the standard ZIP experience. URL submissions reuse community-app's Topgear flow and exact Wipro instructions, submission diff --git a/src/apps/opportunities/src/components/ChallengeSubmissionUpload.spec.tsx b/src/apps/opportunities/src/components/ChallengeSubmissionUpload.spec.tsx index b0be02056..84b79c8be 100644 --- a/src/apps/opportunities/src/components/ChallengeSubmissionUpload.spec.tsx +++ b/src/apps/opportunities/src/components/ChallengeSubmissionUpload.spec.tsx @@ -25,6 +25,7 @@ import { const mockRecordAnalyticsEvent = jest.fn() jest.mock('~/config', () => ({ + AppSubdomain: { topgear: 'topgear' }, EnvironmentConfig: { TOPGEAR_ALLOWED_SUBMISSIONS_DOMAINS: [ 'wipro365.sharepoint.com', diff --git a/src/apps/opportunities/src/pages/ChallengeDetailsPage.topgear-submission.spec.tsx b/src/apps/opportunities/src/pages/ChallengeDetailsPage.topgear-submission.spec.tsx new file mode 100644 index 000000000..037627366 --- /dev/null +++ b/src/apps/opportunities/src/pages/ChallengeDetailsPage.topgear-submission.spec.tsx @@ -0,0 +1,149 @@ +/* eslint-disable import/no-extraneous-dependencies, ordered-imports/ordered-imports */ +import '@testing-library/jest-dom' +import { fireEvent, render, screen, waitFor, within } from '@testing-library/react' +import { MemoryRouter, Route, Routes } from 'react-router-dom' +import { SWRConfig } from 'swr' + +import { ChallengeOpportunity } from '../models' +import { + createChallengeSubmission, + createChallengeUrlSubmission, + getChallengeOpportunity, + getChallengeRegistration, + getChallengeSubmissions, +} from '../services' + +import { ChallengeDetailsPage } from './ChallengeDetailsPage' + +let mockSubdomain = 'www' + +jest.mock('~/config', () => ({ + AppSubdomain: { topgear: 'topgear' }, + EnvironmentConfig: { + REVIEW_APP_URL: 'https://review.topcoder-dev.com', + get SUBDOMAIN(): string { return mockSubdomain }, + TOPGEAR: { GROUP_ID: 'topgear-group' }, + TOPGEAR_ALLOWED_SUBMISSIONS_DOMAINS: ['wipro365.sharepoint.com'], + URLS: { + TERMS_OF_USE: 'https://www.topcoder-dev.com/terms', + TOPGEAR_TERMS: 'https://topgear.topcoder-dev.com/challenges/terms/detail/topgear-terms', + }, + }, +}), { virtual: true }) +jest.mock('~/libs/core', () => ({ + recordAnalyticsEvent: jest.fn(), + useProfileContext: () => ({ initialized: true, profile: { handle: 'coder', userId: 123 } }), +}), { virtual: true }) +jest.mock('~/libs/cms', () => ({}), { virtual: true }) +jest.mock('~/libs/ui', () => { + /** Renders a placeholder icon without loading the shared UI library; never throws. */ + const Icon = (): JSX.Element => + return { + ConfirmModal: (): JSX.Element => <>, + IconOutline: new Proxy({}, { get: () => Icon }), + LoadingSpinner: (): JSX.Element => Loading, + } +}, { virtual: true }) +jest.mock('react-toastify', () => ({ + toast: { error: jest.fn(), success: jest.fn() }, +})) +jest.mock('../components', () => ({ + ChallengeDescription: (): JSX.Element =>
Requirements
, + ChallengeDetailHeader: jest.requireActual('../components/ChallengeDetailHeader').ChallengeDetailHeader, + ChallengeSidebar: (): JSX.Element =>