From 621f8982f1341f4726857b3e14cf5542c5438d2f Mon Sep 17 00:00:00 2001 From: Justin Date: Tue, 31 May 2022 11:20:32 -0400 Subject: [PATCH] Allow guest browsing on Profiles and Statuses --- .../features/ui/__tests__/index.test.tsx | 87 +++++++++++++++++++ app/soapbox/features/ui/index.tsx | 12 ++- app/soapbox/jest/test-setup.ts | 14 +++ 3 files changed, 110 insertions(+), 3 deletions(-) create mode 100644 app/soapbox/features/ui/__tests__/index.test.tsx diff --git a/app/soapbox/features/ui/__tests__/index.test.tsx b/app/soapbox/features/ui/__tests__/index.test.tsx new file mode 100644 index 000000000..e4a360dff --- /dev/null +++ b/app/soapbox/features/ui/__tests__/index.test.tsx @@ -0,0 +1,87 @@ +import { Map as ImmutableMap } from 'immutable'; +import React from 'react'; +import { Route, Switch } from 'react-router-dom'; + +import { render, screen, waitFor } from '../../../jest/test-helpers'; +import { normalizeAccount } from '../../../normalizers'; +import UI from '../index'; + +const TestableComponent = () => ( + + + + + Sign in + +); + +describe('', () => { + let store; + + beforeEach(() => { + store = { + me: false, + accounts: ImmutableMap({ + '1': normalizeAccount({ + id: '1', + acct: 'username', + display_name: 'My name', + avatar: 'test.jpg', + }), + }), + }; + }); + + describe('when logged out', () => { + describe('with guest experience disabled', () => { + beforeEach(() => { + store = { ...store, soapbox: ImmutableMap({ guestExperience: false }) }; + }); + + describe('when viewing a Profile Page', () => { + it('should render the Profile page', async() => { + render( + , + {}, + store, + { initialEntries: ['/@username'] }, + ); + + await waitFor(() => { + expect(screen.getByTestId('cta-banner')).toHaveTextContent('Sign up now to discuss'); + }); + }); + }); + + describe('when viewing a Status Page', () => { + it('should render the Status page', async() => { + render( + , + {}, + store, + { initialEntries: ['/@username/posts/12'] }, + ); + + await waitFor(() => { + expect(screen.getByTestId('cta-banner')).toHaveTextContent('Sign up now to discuss'); + }); + }); + }); + + describe('when viewing any other page', () => { + it('should redirect to the login page', async() => { + render( + , + {}, + store, + { initialEntries: ['/@username/media'] }, + ); + + await waitFor(() => { + expect(screen.getByTestId('sign-in')).toHaveTextContent('Sign in'); + }); + }); + }); + }); + }); +}); diff --git a/app/soapbox/features/ui/index.tsx b/app/soapbox/features/ui/index.tsx index 1ebfc30a0..06591af82 100644 --- a/app/soapbox/features/ui/index.tsx +++ b/app/soapbox/features/ui/index.tsx @@ -5,8 +5,7 @@ import React, { useState, useEffect, useRef, useCallback } from 'react'; import { HotKeys } from 'react-hotkeys'; import { defineMessages, useIntl } from 'react-intl'; import { useDispatch } from 'react-redux'; -import { Switch, useHistory } from 'react-router-dom'; -import { Redirect } from 'react-router-dom'; +import { Switch, useHistory, matchPath, Redirect } from 'react-router-dom'; import { fetchFollowRequests } from 'soapbox/actions/accounts'; import { fetchReports, fetchUsers, fetchConfig } from 'soapbox/actions/admin'; @@ -608,7 +607,14 @@ const UI: React.FC = ({ children }) => { // Wait for login to succeed or fail if (me === null) return null; - if (!me && !guestExperience) { + const isProfileOrStatusPage = !!matchPath( + history.location.pathname, + ['/@:username', '/@:username/posts/:statusId'], + ); + + // Require login if Guest Experience is disabled and we're not trying + // to render a Profile or Status. + if (!me && (!guestExperience && !isProfileOrStatusPage)) { cacheCurrentUrl(history.location); return ; } diff --git a/app/soapbox/jest/test-setup.ts b/app/soapbox/jest/test-setup.ts index 6456e3e84..0052388b0 100644 --- a/app/soapbox/jest/test-setup.ts +++ b/app/soapbox/jest/test-setup.ts @@ -15,3 +15,17 @@ jest.mock('uuid', () => ({ v4: jest.fn(() => '1') })); const intersectionObserverMock = () => ({ observe: () => null, disconnect: () => null }); window.IntersectionObserver = jest.fn().mockImplementation(intersectionObserverMock); + +Object.defineProperty(window, 'matchMedia', { + writable: true, + value: jest.fn().mockImplementation(query => ({ + matches: false, + media: query, + onchange: null, + addListener: jest.fn(), // Deprecated + removeListener: jest.fn(), // Deprecated + addEventListener: jest.fn(), + removeEventListener: jest.fn(), + dispatchEvent: jest.fn(), + })), +});