Skip to content
Open
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
82 changes: 80 additions & 2 deletions src/actions/__tests__/media-upload-actions.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,16 @@
import configureStore from "redux-mock-store";
import thunk from "redux-thunk";
import flushPromises from "flush-promises";
import { getRequest } from "openstack-uicore-foundation/lib/utils/actions";
import { getMediaUpload } from "../media-upload-actions";
import {
getRequest,
snackbarErrorHandler
} from "openstack-uicore-foundation/lib/utils/actions";
import {
getAllMediaUploadTypes,
getMediaUpload
} from "../media-upload-actions";
import * as methods from "../../utils/methods";
import { MAX_PER_PAGE } from "../../utils/constants";

jest.mock("openstack-uicore-foundation/lib/utils/actions", () => ({
__esModule: true,
Expand Down Expand Up @@ -72,3 +79,74 @@ describe("getMediaUpload", () => {
expect(actionTypes).toContain("RECEIVE_MEDIA_UPLOAD");
});
});

describe("getAllMediaUploadTypes", () => {
const middlewares = [thunk];
const mockStore = configureStore(middlewares);
const ENDPOINT = "https://api.test/api/v1/summits/42/media-upload-types";

let requestedParams;

// One row per page, named after its page, so the accumulated list mirrors
// exactly which pages the thunk asked for and in what order it merged them.
const mockPagedRequest = (lastPage) => {
getRequest.mockImplementation(() => (params) => () => {
requestedParams.push(params);
return Promise.resolve({
response: {
last_page: lastPage,
data: [{ id: params.page, name: `type-${params.page}` }]
}
});
});
};

beforeEach(() => {
requestedParams = [];
// getRequest is a module-level jest.fn() shared with the suites above;
// restoreAllMocks does not reset its call history.
getRequest.mockClear();
window.API_BASE_URL = "https://api.test";
jest.spyOn(methods, "getAccessTokenSafely").mockResolvedValue("TOKEN");
});

afterEach(() => {
jest.restoreAllMocks();
delete window.API_BASE_URL;
});

it("loads every remaining page and concatenates them in page order", async () => {
mockPagedRequest(4);
const store = mockStore({});

const result = await store.dispatch(getAllMediaUploadTypes(42));

expect(requestedParams.map((p) => p.page).sort((a, b) => a - b)).toEqual([
1, 2, 3, 4
]);
// Promise.all resolves in input order, so page order survives the fan-out.
expect(result.map((type) => type.name)).toEqual([
"type-1",
"type-2",
"type-3",
"type-4"
]);
});

it("requests only the fields the filter renders, sorted by name, through getRequest", async () => {
mockPagedRequest(1);
const store = mockStore({});

await store.dispatch(getAllMediaUploadTypes(42));

expect(requestedParams[0]).toEqual({
access_token: "TOKEN",
order: "name",
per_page: MAX_PER_PAGE,
fields: "id,name",
page: 1
});
expect(getRequest.mock.calls[0][2]).toBe(ENDPOINT);
expect(getRequest.mock.calls[0][3]).toBe(snackbarErrorHandler);
});
});
51 changes: 49 additions & 2 deletions src/actions/media-upload-actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
* */
import T from "i18n-react/dist/i18n-react";
import URI from "urijs";
import pLimit from "p-limit";
import {
getRequest,
putRequest,
Expand All @@ -27,8 +28,14 @@ import {
fetchErrorHandler
} from "openstack-uicore-foundation/lib/utils/actions";
import debounce from "lodash/debounce";
import { getAccessTokenSafely } from "../utils/methods";
import { DEBOUNCE_WAIT, DEFAULT_PER_PAGE } from "../utils/constants";
import { getAccessTokenSafely, range } from "../utils/methods";
import {
DEBOUNCE_WAIT,
DEFAULT_PER_PAGE,
MAX_PER_PAGE,
TEN,
TWO
} from "../utils/constants";

URI.escapeQuerySpace = false;

Expand Down Expand Up @@ -142,6 +149,46 @@ export const queryMediaUploads = debounce(async (summitId, input, callback) => {
.catch(fetchErrorHandler);
}, DEBOUNCE_WAIT);

export const getAllMediaUploadTypes = (summitId) => async (dispatch) => {
const accessToken = await getAccessTokenSafely();
const endpoint = `${window.API_BASE_URL}/api/v1/summits/${summitId}/media-upload-types`;
const baseParams = {
access_token: accessToken,
order: "name",
per_page: MAX_PER_PAGE,
fields: "id,name"
};
const getPage = (page) =>
getRequest(
createAction("DUMMY"),
createAction("DUMMY"),
endpoint,
snackbarErrorHandler
)({ ...baseParams, page })(dispatch);
const limit = pLimit(TEN);

return (
getPage(1)
.then(({ response }) => {
const { last_page: lastPage, data: firstPageData } = response;
if (lastPage <= 1) return firstPageData;
// local range() is stop-INCLUSIVE: range(TWO, lastPage, 1) === [2..lastPage]
return Promise.all(
range(TWO, lastPage, 1).map((page) => limit(() => getPage(page)))
).then((responses) => {
// Promise.all preserves input order -> page-order accumulation.
const accumulated = [...firstPageData];
responses.forEach(({ response: pageResponse }) => {
accumulated.push(...pageResponse.data);
});
return accumulated;
});
})
// Swallow the rejection since message is already shown by error handler
.catch(() => [])
);
};

export const resetMediaUploadForm = () => (dispatch) => {
dispatch(createAction(RESET_MEDIA_UPLOAD_FORM)({}));
};
Expand Down
Loading
Loading