@plone/volto
Version:
Volto
472 lines (448 loc) • 14.1 kB
JavaScript
import {
protectLoadStart,
protectLoadEnd,
loadProtector,
} from './storeProtectLoadUtils';
import * as Url from '../helpers/Url/Url';
const tick = async () => new Promise((resolve) => setTimeout(resolve, 0));
Object.defineProperty(Url, 'isCmsUi', {
value: vi.fn((path) => locationMap[path]),
writable: true,
});
let locationMap;
describe('storeProtectLoadUtils', () => {
describe('protectLoadStart middleware', () => {
test('idle', () => {
const dispatch = vi.fn();
const getState = vi.fn(() => ({
router: {
location: {
pathname: '/PATH',
},
},
}));
const next = vi.fn(() => 'NEXT');
const action = { type: 'ANY' };
const result = protectLoadStart({ dispatch, getState })(next)(action);
expect(dispatch).toHaveBeenCalledTimes(0);
expect(next).toHaveBeenCalledWith(action);
expect(result).toBe('NEXT');
});
const testLocationChange =
({ locationMap, resetBeforeFetch }) =>
() => {
const dispatch = vi.fn();
const getState = vi.fn(() => ({
router: {
location: {
pathname: '/PATH',
},
},
}));
const next = vi.fn(() => 'NEXT');
const action = {
type: '@@router/LOCATION_CHANGE',
payload: { location: { pathname: '/NEW-PATH' } },
};
Url.isCmsUi = vi.fn((path) => locationMap[path]);
const result = protectLoadStart({ dispatch, getState })(next)(action);
expect(dispatch).toHaveBeenCalledWith({
type: '@@loadProtector/START',
location: { pathname: '/NEW-PATH' },
resetBeforeFetch,
});
expect(next).toHaveBeenCalledWith(action);
expect(result).toBe('NEXT');
};
const testLocationSkipped =
({ locationMap }) =>
() => {
const dispatch = vi.fn();
const getState = vi.fn(() => ({
router: {
location: {
pathname: '/PATH',
},
},
}));
const next = vi.fn(() => 'NEXT');
const action = {
type: '@@router/LOCATION_CHANGE',
payload: { location: { pathname: '/NEW-PATH' } },
};
Url.isCmsUi = vi.fn((path) => locationMap[path]);
const result = protectLoadStart({ dispatch, getState })(next)(action);
expect(dispatch).toHaveBeenCalledWith({
type: '@@loadProtector/SKIPPED',
location: { pathname: '/NEW-PATH' },
});
expect(next).toHaveBeenCalledWith(action);
expect(result).toBe('NEXT');
};
describe('location change', () => {
test(
'non content => content',
testLocationChange({
locationMap: { '/PATH': true, '/NEW-PATH': false },
resetBeforeFetch: true,
}),
);
test(
'content => content',
testLocationChange({
locationMap: { '/PATH': false, '/NEW-PATH': false },
resetBeforeFetch: false,
}),
);
test(
'content => non content',
testLocationSkipped({
locationMap: { '/PATH': false, '/NEW-PATH': true },
}),
);
test(
'non content => non content',
testLocationSkipped({
locationMap: { '/PATH': true, '/NEW-PATH': true },
}),
);
});
test('skips functional actions', () => {
const dispatch = vi.fn();
const getState = vi.fn(() => ({
router: {
location: {
pathname: '/PATH',
},
},
}));
const next = vi.fn(() => 'NEXT');
const action = () => {};
const result = protectLoadStart({ dispatch, getState })(next)(action);
expect(dispatch).toHaveBeenCalledTimes(0);
expect(next).toHaveBeenCalledWith(action);
expect(result).toBe('NEXT');
});
});
describe('protectLoadEnd middleware', () => {
test('idle', async () => {
const dispatch = vi.fn();
const getState = vi.fn(() => ({
loadProtector: {
isCounting: false,
},
}));
const next = vi.fn(() => 'NEXT');
const action = { type: 'ANY' };
const result = protectLoadEnd({ dispatch, getState })(next)(action);
expect(dispatch).toHaveBeenCalledTimes(0);
expect(next).toHaveBeenCalledWith(action);
expect(result).toBe('NEXT');
await tick();
expect(dispatch).toHaveBeenCalledTimes(0);
});
test('not dispatching', async () => {
const dispatch = vi.fn();
const getState = vi.fn(() => ({
loadProtector: {
isCounting: true,
},
}));
const next = vi.fn(() => 'NEXT');
const action = { type: 'ANY' };
const result = protectLoadEnd({ dispatch, getState })(next)(action);
expect(dispatch).toHaveBeenCalledTimes(0);
expect(next).toHaveBeenCalledWith(action);
expect(result).toBe('NEXT');
await tick();
expect(dispatch).toHaveBeenCalledTimes(0);
});
test('skip functional actions', async () => {
const dispatch = vi.fn();
const getState = vi.fn(() => ({
loadProtector: {
isCounting: true,
},
}));
const next = vi.fn(() => 'NEXT');
const action = () => {};
const result = protectLoadEnd({ dispatch, getState })(next)(action);
expect(dispatch).toHaveBeenCalledTimes(0);
expect(next).toHaveBeenCalledWith(action);
expect(result).toBe('NEXT');
await tick();
expect(dispatch).toHaveBeenCalledTimes(0);
});
test('resetting', async () => {
const dispatch = vi.fn();
const getState = vi.fn(() => ({
loadProtector: {
resetBeforeFetch: true,
},
}));
const next = vi.fn(() => 'NEXT');
const action = { type: 'GET_CONTENT_PENDING' };
const result = protectLoadEnd({ dispatch, getState })(next)(action);
expect(dispatch).toHaveBeenCalledWith({ type: 'RESET_CONTENT' });
expect(next).toHaveBeenCalledWith(action);
expect(result).toBe('NEXT');
await tick();
expect(dispatch).toHaveBeenCalledTimes(1);
});
test('not resetting on content-content transition ', async () => {
const dispatch = vi.fn();
const getState = vi.fn(() => ({
loadProtector: {
isCounting: true,
resetBeforeFetch: false,
},
}));
const next = vi.fn(() => 'NEXT');
const action = { type: 'GET_CONTENT_PENDING' };
const result = protectLoadEnd({ dispatch, getState })(next)(action);
expect(dispatch).toHaveBeenCalledTimes(0);
expect(next).toHaveBeenCalledWith(action);
expect(result).toBe('NEXT');
await tick();
expect(dispatch).toHaveBeenCalledTimes(0);
});
test('counting down when success', async () => {
const dispatch = vi.fn();
const getState = vi.fn(() => ({
loadProtector: {
isCounting: true,
requestCount: 2,
},
}));
const next = vi.fn(() => 'NEXT');
const action = { type: 'ANY_SUCCESS' };
const result = protectLoadEnd({ dispatch, getState })(next)(action);
expect(dispatch).toHaveBeenCalledTimes(0);
expect(next).toHaveBeenCalledWith(action);
expect(result).toBe('NEXT');
await tick();
expect(dispatch).toHaveBeenCalledTimes(0);
});
test('counting down when failure', async () => {
const dispatch = vi.fn();
const getState = vi.fn(() => ({
loadProtector: {
isCounting: true,
requestCount: 2,
},
}));
const next = vi.fn(() => 'NEXT');
const action = { type: 'ANY_FAIL' };
const result = protectLoadEnd({ dispatch, getState })(next)(action);
expect(dispatch).toHaveBeenCalledTimes(0);
expect(next).toHaveBeenCalledWith(action);
expect(result).toBe('NEXT');
await tick();
expect(dispatch).toHaveBeenCalledTimes(0);
});
test('ending protect when success', async () => {
const dispatch = vi.fn();
const getState = vi.fn(() => ({
loadProtector: {
isCounting: true,
requestCount: 1,
},
}));
const next = vi.fn(() => 'NEXT');
const action = { type: 'ANY_SUCCESS' };
const result = protectLoadEnd({ dispatch, getState })(next)(action);
expect(dispatch).toHaveBeenCalledTimes(0);
expect(next).toHaveBeenCalledWith(action);
expect(result).toBe('NEXT');
await tick();
expect(dispatch).toHaveBeenCalledTimes(1);
expect(dispatch).toHaveBeenCalledWith({ type: '@@loadProtector/END' });
});
test('ending protect when failure', async () => {
const dispatch = vi.fn();
const getState = vi.fn(() => ({
loadProtector: {
isCounting: true,
requestCount: 1,
},
}));
const next = vi.fn(() => 'NEXT');
const action = { type: 'ANY_FAIL' };
const result = protectLoadEnd({ dispatch, getState })(next)(action);
expect(dispatch).toHaveBeenCalledTimes(0);
expect(next).toHaveBeenCalledWith(action);
expect(result).toBe('NEXT');
await tick();
expect(dispatch).toHaveBeenCalledTimes(1);
expect(dispatch).toHaveBeenCalledWith({ type: '@@loadProtector/END' });
});
});
describe('loadProtector store', () => {
test('PROTECT_START', () => {
const state = {
foo: 'BAR',
isCounting: false,
};
const action = { type: '@@loadProtector/START' };
const result = loadProtector(state, action);
expect(result).toEqual({
foo: 'BAR',
requestCount: 0,
isCounting: true,
});
});
test('PROTECT_END', () => {
const state = {
foo: 'BAR',
requestCount: 1,
isCounting: true,
resetBeforeFetch: false,
};
const action = { type: '@@loadProtector/END' };
const result = loadProtector(state, action);
expect(result).toEqual({
foo: 'BAR',
requestCount: 0,
isCounting: false,
resetBeforeFetch: false,
});
});
test('PROTECT_SKIPPED', () => {
const state = {
foo: 'BAR',
requestCount: 1,
isCounting: true,
resetBeforeFetch: false,
};
const action = {
type: '@@loadProtector/SKIPPED',
location: { pathname: '/NEW-PATH' },
};
const result = loadProtector(state, action);
expect(result).toEqual({
foo: 'BAR',
requestCount: 0,
isCounting: false,
resetBeforeFetch: false,
postponedLocation: null,
location: { pathname: '/NEW-PATH' },
});
});
test('GET_CONTENT_SUCCESS pass when not counting', () => {
const state = {
foo: 'BAR',
isCounting: false,
};
const action = {
type: 'GET_CONTENT_SUCCESS',
};
const result = loadProtector(state, action);
expect(result).toEqual({
foo: 'BAR',
isCounting: false,
});
});
test('GET_CONTENT_FAIL pass when not counting', () => {
const state = {
foo: 'BAR',
isCounting: false,
};
const action = {
type: 'GET_CONTENT_FAIL',
};
const result = loadProtector(state, action);
expect(result).toEqual({
foo: 'BAR',
isCounting: false,
});
});
test('GET_CONTENT_SUCCESS when counting', () => {
const state = {
foo: 'BAR',
requestCount: 1,
isCounting: true,
postponedLocation: { pathname: '/NEW-PATH' },
};
const action = {
type: 'GET_CONTENT_SUCCESS',
};
const result = loadProtector(state, action);
expect(result).toEqual({
foo: 'BAR',
requestCount: 0,
isCounting: true,
postponedLocation: null,
location: { pathname: '/NEW-PATH' },
});
});
test('GET_CONTENT_FAIL when counting', () => {
const state = {
foo: 'BAR',
requestCount: 1,
isCounting: true,
postponedLocation: { pathname: '/NEW-PATH' },
};
const action = {
type: 'GET_CONTENT_FAIL',
};
const result = loadProtector(state, action);
expect(result).toEqual({
foo: 'BAR',
requestCount: 0,
isCounting: true,
postponedLocation: null,
location: { pathname: '/NEW-PATH' },
});
});
test('RESET_CONTENT will remove the reset condition', () => {
const state = {
foo: 'BAR',
resetBeforeFetch: true,
};
const action = {
type: 'RESET_CONTENT',
};
const result = loadProtector(state, action);
expect(result).toEqual({
foo: 'BAR',
resetBeforeFetch: false,
});
});
describe('pass when not counting', () => {
const expectPass = (action, requestCount) => () => {
const state = {
foo: 'BAR',
requestCount,
isCounting: false,
};
const result = loadProtector(state, action);
expect(result).toEqual({
foo: 'BAR',
requestCount,
isCounting: false,
});
};
test('pending', expectPass({ type: 'ANY_PENDING' }, 2));
test('success', expectPass({ type: 'ANY_SUCCESS' }, 2));
test('failure', expectPass({ type: 'ANY_FAIL' }, 2));
});
describe('counting', () => {
const expectCount = (action, from, to) => () => {
const state = {
foo: 'BAR',
requestCount: from,
isCounting: true,
};
const result = loadProtector(state, action);
expect(result).toEqual({
foo: 'BAR',
requestCount: to,
isCounting: true,
});
};
test('pending counts up', expectCount({ type: 'ANY_PENDING' }, 2, 3));
test('success counts down', expectCount({ type: 'ANY_SUCCESS' }, 2, 1));
test('failure counts down', expectCount({ type: 'ANY_FAIL' }, 2, 1));
});
});
});