Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
import { ListingContainer } from 'containers/challenge-listing/Listing';
import { BUCKETS } from 'utils/challenge-listing/buckets';

/**
* Creates a challenge-listing container configured for an auth-change test.
* The returned instance is used to invoke the lifecycle method directly,
* without mounting the full connected challenge-listing tree.
*
* @param {String|null} tokenV3 Current Topcoder v3 token.
* @param {String} activeBucket Currently selected challenge-listing bucket.
* @returns {Object} Container instance and its mocked props.
*/
function createListing(tokenV3, activeBucket) {
const props = {
activeBucket,
auth: {
tokenV3,
user: { userId: 123, handle: 'member' },
},
communitiesList: { data: [] },
communityId: null,
dropReviewOpportunities: jest.fn(),
filter: {},
filterState: { recommended: false },
getCommunitiesList: jest.fn(),
getReviewOpportunities: jest.fn(),
loading: false,
selectBucketDone: jest.fn(),
setFilter: jest.fn(),
sorts: {},
};
const instance = new ListingContainer(props);
instance.getBackendFilter = jest.fn(() => ({ back: {}, front: {} }));
instance.reloadChallenges = jest.fn();
return { instance, props };
}

describe('challenge listing review opportunities authentication', () => {
beforeEach(() => {
jest.useFakeTimers();
});

afterEach(() => {
jest.clearAllTimers();
jest.useRealTimers();
});

test('reloads the first review-opportunity page when authentication arrives', () => {
const { instance, props } = createListing(
'member-token',
BUCKETS.REVIEW_OPPORTUNITIES,
);

instance.componentDidUpdate({
...props,
auth: { ...props.auth, tokenV3: null },
});

expect(props.dropReviewOpportunities).toHaveBeenCalledTimes(1);
expect(props.getReviewOpportunities).toHaveBeenCalledWith(0, 'member-token');
});

test('reloads anonymously after logout so restricted rows cannot remain cached', () => {
const { instance, props } = createListing(
null,
BUCKETS.REVIEW_OPPORTUNITIES,
);

instance.componentDidUpdate({
...props,
auth: { ...props.auth, tokenV3: 'member-token' },
});

expect(props.dropReviewOpportunities).toHaveBeenCalledTimes(1);
expect(props.getReviewOpportunities).toHaveBeenCalledWith(0, null);
});

test('clears cached opportunities without preloading an inactive bucket', () => {
const { instance, props } = createListing('member-token', BUCKETS.ALL);

instance.componentDidUpdate({
...props,
auth: { ...props.auth, tokenV3: null },
});

expect(props.dropReviewOpportunities).toHaveBeenCalledTimes(1);
expect(props.getReviewOpportunities).not.toHaveBeenCalled();
});
});
30 changes: 30 additions & 0 deletions __tests__/shared/reducers/challenge-listing/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import actions from 'actions/challenge-listing';
import reducer from 'reducers/challenge-listing';

describe('challenge listing review-opportunity cache', () => {
test('drops caller-specific review opportunities without changing other buckets', () => {
const initialState = reducer(undefined, { type: '@@INIT' });
const allChallenges = [{ id: 'public-challenge' }];
const populatedState = {
...initialState,
allChallenges,
allReviewOpportunitiesLoaded: true,
lastRequestedPageOfReviewOpportunities: 3,
loadingReviewOpportunitiesUUID: 'old-request',
reviewOpportunities: [{ id: 'restricted-opportunity' }],
};

const nextState = reducer(
populatedState,
actions.challengeListing.dropReviewOpportunities(),
);

expect(nextState).toEqual(expect.objectContaining({
allReviewOpportunitiesLoaded: false,
lastRequestedPageOfReviewOpportunities: -1,
loadingReviewOpportunitiesUUID: '',
reviewOpportunities: [],
}));
expect(nextState.allChallenges).toBe(allChallenges);
});
});
1 change: 1 addition & 0 deletions src/shared/actions/challenge-listing/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -590,6 +590,7 @@ export default createActions({
DROP_PAST_CHALLENGES: _.noop,
DROP_MY_PAST_CHALLENGES: _.noop,
DROP_RECOMMENDED_CHALLENGES: _.noop,
DROP_REVIEW_OPPORTUNITIES: _.noop,

// GET_ALL_ACTIVE_CHALLENGES_INIT: getAllActiveChallengesInit,
// GET_ALL_ACTIVE_CHALLENGES_DONE: getAllActiveChallengesDone,
Expand Down
12 changes: 11 additions & 1 deletion src/shared/containers/challenge-listing/Listing/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ export class ListingContainer extends React.Component {

componentDidUpdate(prevProps) {
const {
// activeBucket,
activeBucket,
auth,
// dropChallenges,
communityId,
Expand All @@ -134,6 +134,8 @@ export class ListingContainer extends React.Component {
dropOpenForRegistrationChallenges,
dropPastChallenges,
getPastChallenges,
dropReviewOpportunities,
getReviewOpportunities,
filterState,
loading,
setFilter,
Expand All @@ -145,6 +147,12 @@ export class ListingContainer extends React.Component {
if (userId !== oldUserId) {
getCommunitiesList(auth);
}
if (prevProps.auth.tokenV3 !== auth.tokenV3) {
dropReviewOpportunities();
if (activeBucket === BUCKETS.REVIEW_OPPORTUNITIES) {
getReviewOpportunities(0, auth.tokenV3);
}
}
// console.log(prevProps);
// const { profile } = auth;
// if (profile) {
Expand Down Expand Up @@ -794,6 +802,7 @@ ListingContainer.propTypes = {
dropOpenForRegistrationChallenges: PT.func.isRequired,
dropActiveChallenges: PT.func.isRequired,
dropPastChallenges: PT.func.isRequired,
dropReviewOpportunities: PT.func.isRequired,
filter: PT.shape().isRequired,
hideSrm: PT.bool,
// hideTcLinksInSidebarFooter: PT.bool,
Expand Down Expand Up @@ -997,6 +1006,7 @@ function mapDispatchToProps(dispatch) {
dispatch(ca.getListDone(uuid, auth));
},
dropPastChallenges: () => dispatch(a.dropPastChallenges()),
dropReviewOpportunities: () => dispatch(a.dropReviewOpportunities()),
getPastChallenges: (page, filter, token, frontFilter) => {
const uuid = shortId();
dispatch(a.getPastChallengesInit(uuid, page, frontFilter));
Expand Down
7 changes: 7 additions & 0 deletions src/shared/reducers/challenge-listing/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -821,6 +821,13 @@ function create(initialState) {
lastRequestedPageOfPastChallenges: -1,
loadingPastChallengesUUID: '',
}),
[a.dropReviewOpportunities]: state => ({
...state,
allReviewOpportunitiesLoaded: false,
reviewOpportunities: [],
lastRequestedPageOfReviewOpportunities: -1,
loadingReviewOpportunitiesUUID: '',
}),
[a.expandTag]: (state, { payload }) => ({
...state,
expandedTags: [...state.expandedTags, payload],
Expand Down
Loading