mirror of
https://github.com/scm-manager/scm-manager.git
synced 2025-11-16 02:06:18 +01:00
use reflow to migrate from flow to typescript
This commit is contained in:
@@ -1,620 +0,0 @@
|
||||
// @flow
|
||||
|
||||
import configureMockStore from "redux-mock-store";
|
||||
import thunk from "redux-thunk";
|
||||
import fetchMock from "fetch-mock";
|
||||
import reducer, {
|
||||
FETCH_CHANGESET,
|
||||
FETCH_CHANGESET_FAILURE,
|
||||
FETCH_CHANGESET_PENDING,
|
||||
FETCH_CHANGESET_SUCCESS,
|
||||
FETCH_CHANGESETS,
|
||||
FETCH_CHANGESETS_FAILURE,
|
||||
FETCH_CHANGESETS_PENDING,
|
||||
FETCH_CHANGESETS_SUCCESS,
|
||||
fetchChangeset,
|
||||
fetchChangesetIfNeeded,
|
||||
fetchChangesets,
|
||||
fetchChangesetsSuccess,
|
||||
fetchChangesetSuccess,
|
||||
getChangeset,
|
||||
getChangesets,
|
||||
getFetchChangesetFailure,
|
||||
getFetchChangesetsFailure,
|
||||
isFetchChangesetPending,
|
||||
isFetchChangesetsPending,
|
||||
selectListAsCollection,
|
||||
shouldFetchChangeset
|
||||
} from "./changesets";
|
||||
|
||||
const branch = {
|
||||
name: "specific",
|
||||
revision: "123",
|
||||
_links: {
|
||||
history: {
|
||||
href:
|
||||
"http://scm.hitchhicker.com/api/v2/repositories/foo/bar/branches/specific/changesets"
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const repository = {
|
||||
namespace: "foo",
|
||||
name: "bar",
|
||||
type: "GIT",
|
||||
_links: {
|
||||
self: {
|
||||
href: "http://scm.hitchhicker.com/api/v2/repositories/foo/bar"
|
||||
},
|
||||
changesets: {
|
||||
href: "http://scm.hitchhicker.com/api/v2/repositories/foo/bar/changesets"
|
||||
},
|
||||
branches: {
|
||||
href:
|
||||
"http://scm.hitchhicker.com/api/v2/repositories/foo/bar/branches/specific/branches"
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const changesets = {};
|
||||
|
||||
describe("changesets", () => {
|
||||
describe("fetching of changesets", () => {
|
||||
const DEFAULT_BRANCH_URL =
|
||||
"http://scm.hitchhicker.com/api/v2/repositories/foo/bar/changesets";
|
||||
const SPECIFIC_BRANCH_URL =
|
||||
"http://scm.hitchhicker.com/api/v2/repositories/foo/bar/branches/specific/changesets";
|
||||
|
||||
const mockStore = configureMockStore([thunk]);
|
||||
|
||||
afterEach(() => {
|
||||
fetchMock.reset();
|
||||
fetchMock.restore();
|
||||
});
|
||||
|
||||
const changesetId = "aba876c0625d90a6aff1494f3d161aaa7008b958";
|
||||
|
||||
it("should fetch changeset", () => {
|
||||
fetchMock.getOnce(DEFAULT_BRANCH_URL + "/" + changesetId, "{}");
|
||||
|
||||
const expectedActions = [
|
||||
{
|
||||
type: FETCH_CHANGESET_PENDING,
|
||||
itemId: "foo/bar/" + changesetId
|
||||
},
|
||||
{
|
||||
type: FETCH_CHANGESET_SUCCESS,
|
||||
payload: {
|
||||
changeset: {},
|
||||
id: changesetId,
|
||||
repository: repository
|
||||
},
|
||||
itemId: "foo/bar/" + changesetId
|
||||
}
|
||||
];
|
||||
|
||||
const store = mockStore({});
|
||||
return store
|
||||
.dispatch(fetchChangeset(repository, changesetId))
|
||||
.then(() => {
|
||||
expect(store.getActions()).toEqual(expectedActions);
|
||||
});
|
||||
});
|
||||
|
||||
it("should fail fetching changeset on error", () => {
|
||||
fetchMock.getOnce(DEFAULT_BRANCH_URL + "/" + changesetId, 500);
|
||||
|
||||
const expectedActions = [
|
||||
{
|
||||
type: FETCH_CHANGESET_PENDING,
|
||||
itemId: "foo/bar/" + changesetId
|
||||
}
|
||||
];
|
||||
|
||||
const store = mockStore({});
|
||||
return store
|
||||
.dispatch(fetchChangeset(repository, changesetId))
|
||||
.then(() => {
|
||||
expect(store.getActions()[0]).toEqual(expectedActions[0]);
|
||||
expect(store.getActions()[1].type).toEqual(FETCH_CHANGESET_FAILURE);
|
||||
expect(store.getActions()[1].payload).toBeDefined();
|
||||
});
|
||||
});
|
||||
|
||||
it("should fetch changeset if needed", () => {
|
||||
fetchMock.getOnce(DEFAULT_BRANCH_URL + "/id3", "{}");
|
||||
|
||||
const expectedActions = [
|
||||
{
|
||||
type: FETCH_CHANGESET_PENDING,
|
||||
itemId: "foo/bar/id3"
|
||||
},
|
||||
{
|
||||
type: FETCH_CHANGESET_SUCCESS,
|
||||
payload: {
|
||||
changeset: {},
|
||||
id: "id3",
|
||||
repository: repository
|
||||
},
|
||||
itemId: "foo/bar/id3"
|
||||
}
|
||||
];
|
||||
|
||||
const store = mockStore({});
|
||||
return store
|
||||
.dispatch(fetchChangesetIfNeeded(repository, "id3"))
|
||||
.then(() => {
|
||||
expect(store.getActions()).toEqual(expectedActions);
|
||||
});
|
||||
});
|
||||
|
||||
it("should not fetch changeset if not needed", () => {
|
||||
fetchMock.getOnce(DEFAULT_BRANCH_URL + "/id1", 500);
|
||||
|
||||
const state = {
|
||||
changesets: {
|
||||
"foo/bar": {
|
||||
byId: {
|
||||
id1: { id: "id1" },
|
||||
id2: { id: "id2" }
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const store = mockStore(state);
|
||||
return expect(
|
||||
store.dispatch(fetchChangesetIfNeeded(repository, "id1"))
|
||||
).toEqual(undefined);
|
||||
});
|
||||
|
||||
it("should fetch changesets for default branch", () => {
|
||||
fetchMock.getOnce(DEFAULT_BRANCH_URL, "{}");
|
||||
|
||||
const expectedActions = [
|
||||
{
|
||||
type: FETCH_CHANGESETS_PENDING,
|
||||
itemId: "foo/bar"
|
||||
},
|
||||
{
|
||||
type: FETCH_CHANGESETS_SUCCESS,
|
||||
payload: {
|
||||
repository,
|
||||
undefined,
|
||||
changesets
|
||||
},
|
||||
itemId: "foo/bar"
|
||||
}
|
||||
];
|
||||
|
||||
const store = mockStore({});
|
||||
return store.dispatch(fetchChangesets(repository)).then(() => {
|
||||
expect(store.getActions()).toEqual(expectedActions);
|
||||
});
|
||||
});
|
||||
|
||||
it("should fetch changesets for specific branch", () => {
|
||||
const itemId = "foo/bar/specific";
|
||||
fetchMock.getOnce(SPECIFIC_BRANCH_URL, "{}");
|
||||
|
||||
const expectedActions = [
|
||||
{
|
||||
type: FETCH_CHANGESETS_PENDING,
|
||||
itemId
|
||||
},
|
||||
{
|
||||
type: FETCH_CHANGESETS_SUCCESS,
|
||||
payload: {
|
||||
repository,
|
||||
branch,
|
||||
changesets
|
||||
},
|
||||
itemId
|
||||
}
|
||||
];
|
||||
|
||||
const store = mockStore({});
|
||||
return store.dispatch(fetchChangesets(repository, branch)).then(() => {
|
||||
expect(store.getActions()).toEqual(expectedActions);
|
||||
});
|
||||
});
|
||||
|
||||
it("should fail fetching changesets on error", () => {
|
||||
const itemId = "foo/bar";
|
||||
fetchMock.getOnce(DEFAULT_BRANCH_URL, 500);
|
||||
|
||||
const expectedActions = [
|
||||
{
|
||||
type: FETCH_CHANGESETS_PENDING,
|
||||
itemId
|
||||
}
|
||||
];
|
||||
|
||||
const store = mockStore({});
|
||||
return store.dispatch(fetchChangesets(repository)).then(() => {
|
||||
expect(store.getActions()[0]).toEqual(expectedActions[0]);
|
||||
expect(store.getActions()[1].type).toEqual(FETCH_CHANGESETS_FAILURE);
|
||||
expect(store.getActions()[1].payload).toBeDefined();
|
||||
});
|
||||
});
|
||||
|
||||
it("should fail fetching changesets for specific branch on error", () => {
|
||||
const itemId = "foo/bar/specific";
|
||||
fetchMock.getOnce(SPECIFIC_BRANCH_URL, 500);
|
||||
|
||||
const expectedActions = [
|
||||
{
|
||||
type: FETCH_CHANGESETS_PENDING,
|
||||
itemId
|
||||
}
|
||||
];
|
||||
|
||||
const store = mockStore({});
|
||||
return store.dispatch(fetchChangesets(repository, branch)).then(() => {
|
||||
expect(store.getActions()[0]).toEqual(expectedActions[0]);
|
||||
expect(store.getActions()[1].type).toEqual(FETCH_CHANGESETS_FAILURE);
|
||||
expect(store.getActions()[1].payload).toBeDefined();
|
||||
});
|
||||
});
|
||||
|
||||
it("should fetch changesets by page", () => {
|
||||
fetchMock.getOnce(DEFAULT_BRANCH_URL + "?page=4", "{}");
|
||||
|
||||
const expectedActions = [
|
||||
{
|
||||
type: FETCH_CHANGESETS_PENDING,
|
||||
itemId: "foo/bar"
|
||||
},
|
||||
{
|
||||
type: FETCH_CHANGESETS_SUCCESS,
|
||||
payload: {
|
||||
repository,
|
||||
undefined,
|
||||
changesets
|
||||
},
|
||||
itemId: "foo/bar"
|
||||
}
|
||||
];
|
||||
|
||||
const store = mockStore({});
|
||||
return store
|
||||
.dispatch(fetchChangesets(repository, undefined, 5))
|
||||
.then(() => {
|
||||
expect(store.getActions()).toEqual(expectedActions);
|
||||
});
|
||||
});
|
||||
|
||||
it("should fetch changesets by branch and page", () => {
|
||||
fetchMock.getOnce(SPECIFIC_BRANCH_URL + "?page=4", "{}");
|
||||
|
||||
const expectedActions = [
|
||||
{
|
||||
type: FETCH_CHANGESETS_PENDING,
|
||||
itemId: "foo/bar/specific"
|
||||
},
|
||||
{
|
||||
type: FETCH_CHANGESETS_SUCCESS,
|
||||
payload: {
|
||||
repository,
|
||||
branch,
|
||||
changesets
|
||||
},
|
||||
itemId: "foo/bar/specific"
|
||||
}
|
||||
];
|
||||
|
||||
const store = mockStore({});
|
||||
return store.dispatch(fetchChangesets(repository, branch, 5)).then(() => {
|
||||
expect(store.getActions()).toEqual(expectedActions);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("changesets reducer", () => {
|
||||
const responseBody = {
|
||||
page: 1,
|
||||
pageTotal: 10,
|
||||
_links: {},
|
||||
_embedded: {
|
||||
changesets: [
|
||||
{ id: "changeset1", author: { mail: "z@phod.com", name: "zaphod" } },
|
||||
{ id: "changeset2", description: "foo" },
|
||||
{ id: "changeset3", description: "bar" }
|
||||
],
|
||||
_embedded: {
|
||||
tags: [],
|
||||
branches: [],
|
||||
parents: []
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
it("should set state to received changesets", () => {
|
||||
const newState = reducer(
|
||||
{},
|
||||
fetchChangesetsSuccess(repository, undefined, responseBody)
|
||||
);
|
||||
expect(newState).toBeDefined();
|
||||
expect(newState["foo/bar"].byId["changeset1"].author.mail).toEqual(
|
||||
"z@phod.com"
|
||||
);
|
||||
expect(newState["foo/bar"].byId["changeset2"].description).toEqual("foo");
|
||||
expect(newState["foo/bar"].byId["changeset3"].description).toEqual("bar");
|
||||
expect(newState["foo/bar"].byBranch[""]).toEqual({
|
||||
entry: {
|
||||
page: 1,
|
||||
pageTotal: 10,
|
||||
_links: {}
|
||||
},
|
||||
entries: ["changeset1", "changeset2", "changeset3"]
|
||||
});
|
||||
});
|
||||
|
||||
it("should store the changeset list to branch", () => {
|
||||
const newState = reducer(
|
||||
{},
|
||||
fetchChangesetsSuccess(repository, branch, responseBody)
|
||||
);
|
||||
|
||||
expect(newState["foo/bar"].byId["changeset1"]).toBeDefined();
|
||||
expect(newState["foo/bar"].byBranch["specific"].entries).toEqual([
|
||||
"changeset1",
|
||||
"changeset2",
|
||||
"changeset3"
|
||||
]);
|
||||
});
|
||||
|
||||
it("should not remove existing changesets", () => {
|
||||
const state = {
|
||||
"foo/bar": {
|
||||
byId: {
|
||||
id2: { id: "id2" },
|
||||
id1: { id: "id1" }
|
||||
},
|
||||
byBranch: {
|
||||
"": {
|
||||
entries: ["id1", "id2"]
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const newState = reducer(
|
||||
state,
|
||||
fetchChangesetsSuccess(repository, undefined, responseBody)
|
||||
);
|
||||
|
||||
const fooBar = newState["foo/bar"];
|
||||
|
||||
expect(fooBar.byBranch[""].entries).toEqual([
|
||||
"changeset1",
|
||||
"changeset2",
|
||||
"changeset3"
|
||||
]);
|
||||
expect(fooBar.byId["id2"]).toEqual({ id: "id2" });
|
||||
expect(fooBar.byId["id1"]).toEqual({ id: "id1" });
|
||||
});
|
||||
|
||||
const responseBodySingleChangeset = {
|
||||
id: "id3",
|
||||
author: {
|
||||
mail: "z@phod.com",
|
||||
name: "zaphod"
|
||||
},
|
||||
date: "2018-09-13T08:46:22Z",
|
||||
description: "added testChangeset",
|
||||
_links: {},
|
||||
_embedded: {
|
||||
tags: [],
|
||||
branches: []
|
||||
}
|
||||
};
|
||||
|
||||
it("should add changeset to state", () => {
|
||||
const newState = reducer(
|
||||
{
|
||||
"foo/bar": {
|
||||
byId: {
|
||||
"id2": {
|
||||
id: "id2",
|
||||
author: { mail: "mail@author.com", name: "author" }
|
||||
}
|
||||
},
|
||||
list: {
|
||||
entry: {
|
||||
page: 1,
|
||||
pageTotal: 10,
|
||||
_links: {}
|
||||
},
|
||||
entries: ["id2"]
|
||||
}
|
||||
}
|
||||
},
|
||||
fetchChangesetSuccess(responseBodySingleChangeset, repository, "id3")
|
||||
);
|
||||
|
||||
expect(newState).toBeDefined();
|
||||
expect(newState["foo/bar"].byId["id3"].description).toEqual(
|
||||
"added testChangeset"
|
||||
);
|
||||
expect(newState["foo/bar"].byId["id3"].author.mail).toEqual("z@phod.com");
|
||||
expect(newState["foo/bar"].byId["id2"]).toBeDefined();
|
||||
expect(newState["foo/bar"].byId["id3"]).toBeDefined();
|
||||
expect(newState["foo/bar"].list).toEqual({
|
||||
entry: {
|
||||
page: 1,
|
||||
pageTotal: 10,
|
||||
_links: {}
|
||||
},
|
||||
entries: ["id2"]
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("changeset selectors", () => {
|
||||
const error = new Error("Something went wrong");
|
||||
|
||||
it("should return changeset", () => {
|
||||
const state = {
|
||||
changesets: {
|
||||
"foo/bar": {
|
||||
byId: {
|
||||
id1: { id: "id1" },
|
||||
id2: { id: "id2" }
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
const result = getChangeset(state, repository, "id1");
|
||||
expect(result).toEqual({ id: "id1" });
|
||||
});
|
||||
|
||||
it("should return null if changeset does not exist", () => {
|
||||
const state = {
|
||||
changesets: {
|
||||
"foo/bar": {
|
||||
byId: {
|
||||
id1: { id: "id1" },
|
||||
id2: { id: "id2" }
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
const result = getChangeset(state, repository, "id3");
|
||||
expect(result).toEqual(null);
|
||||
});
|
||||
|
||||
it("should return true if changeset does not exist", () => {
|
||||
const state = {
|
||||
changesets: {
|
||||
"foo/bar": {
|
||||
byId: {
|
||||
id1: { id: "id1" },
|
||||
id2: { id: "id2" }
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
const result = shouldFetchChangeset(state, repository, "id3");
|
||||
expect(result).toEqual(true);
|
||||
});
|
||||
|
||||
it("should return false if changeset exists", () => {
|
||||
const state = {
|
||||
changesets: {
|
||||
"foo/bar": {
|
||||
byId: {
|
||||
id1: { id: "id1" },
|
||||
id2: { id: "id2" }
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
const result = shouldFetchChangeset(state, repository, "id2");
|
||||
expect(result).toEqual(false);
|
||||
});
|
||||
|
||||
it("should return true, when fetching changeset is pending", () => {
|
||||
const state = {
|
||||
pending: {
|
||||
[FETCH_CHANGESET + "/foo/bar/id1"]: true
|
||||
}
|
||||
};
|
||||
|
||||
expect(isFetchChangesetPending(state, repository, "id1")).toBeTruthy();
|
||||
});
|
||||
|
||||
it("should return false, when fetching changeset is not pending", () => {
|
||||
expect(isFetchChangesetPending({}, repository, "id1")).toEqual(false);
|
||||
});
|
||||
|
||||
it("should return error if fetching changeset failed", () => {
|
||||
const state = {
|
||||
failure: {
|
||||
[FETCH_CHANGESET + "/foo/bar/id1"]: error
|
||||
}
|
||||
};
|
||||
|
||||
expect(getFetchChangesetFailure(state, repository, "id1")).toEqual(error);
|
||||
});
|
||||
|
||||
it("should return false if fetching changeset did not fail", () => {
|
||||
expect(getFetchChangesetFailure({}, repository, "id1")).toBeUndefined();
|
||||
});
|
||||
|
||||
it("should get all changesets for a given repository", () => {
|
||||
const state = {
|
||||
changesets: {
|
||||
"foo/bar": {
|
||||
byId: {
|
||||
id2: { id: "id2" },
|
||||
id1: { id: "id1" }
|
||||
},
|
||||
byBranch: {
|
||||
"": {
|
||||
entries: ["id1", "id2"]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
const result = getChangesets(state, repository);
|
||||
expect(result).toEqual([{ id: "id1" }, { id: "id2" }]);
|
||||
});
|
||||
|
||||
it("should return true, when fetching changesets is pending", () => {
|
||||
const state = {
|
||||
pending: {
|
||||
[FETCH_CHANGESETS + "/foo/bar"]: true
|
||||
}
|
||||
};
|
||||
|
||||
expect(isFetchChangesetsPending(state, repository)).toBeTruthy();
|
||||
});
|
||||
|
||||
it("should return false, when fetching changesets is not pending", () => {
|
||||
expect(isFetchChangesetsPending({}, repository)).toEqual(false);
|
||||
});
|
||||
|
||||
it("should return error if fetching changesets failed", () => {
|
||||
const state = {
|
||||
failure: {
|
||||
[FETCH_CHANGESETS + "/foo/bar"]: error
|
||||
}
|
||||
};
|
||||
|
||||
expect(getFetchChangesetsFailure(state, repository)).toEqual(error);
|
||||
});
|
||||
|
||||
it("should return false if fetching changesets did not fail", () => {
|
||||
expect(getFetchChangesetsFailure({}, repository)).toBeUndefined();
|
||||
});
|
||||
|
||||
it("should return list as collection for the default branch", () => {
|
||||
const state = {
|
||||
changesets: {
|
||||
"foo/bar": {
|
||||
byId: {
|
||||
id2: { id: "id2" },
|
||||
id1: { id: "id1" }
|
||||
},
|
||||
byBranch: {
|
||||
"": {
|
||||
entry: {
|
||||
page: 1,
|
||||
pageTotal: 10,
|
||||
_links: {}
|
||||
},
|
||||
entries: ["id1", "id2"]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const collection = selectListAsCollection(state, repository);
|
||||
expect(collection.page).toBe(1);
|
||||
expect(collection.pageTotal).toBe(10);
|
||||
});
|
||||
});
|
||||
});
|
||||
678
scm-ui/ui-webapp/src/repos/modules/changesets.test.ts
Normal file
678
scm-ui/ui-webapp/src/repos/modules/changesets.test.ts
Normal file
@@ -0,0 +1,678 @@
|
||||
import configureMockStore from 'redux-mock-store';
|
||||
import thunk from 'redux-thunk';
|
||||
import fetchMock from 'fetch-mock';
|
||||
import reducer, {
|
||||
FETCH_CHANGESET,
|
||||
FETCH_CHANGESET_FAILURE,
|
||||
FETCH_CHANGESET_PENDING,
|
||||
FETCH_CHANGESET_SUCCESS,
|
||||
FETCH_CHANGESETS,
|
||||
FETCH_CHANGESETS_FAILURE,
|
||||
FETCH_CHANGESETS_PENDING,
|
||||
FETCH_CHANGESETS_SUCCESS,
|
||||
fetchChangeset,
|
||||
fetchChangesetIfNeeded,
|
||||
fetchChangesets,
|
||||
fetchChangesetsSuccess,
|
||||
fetchChangesetSuccess,
|
||||
getChangeset,
|
||||
getChangesets,
|
||||
getFetchChangesetFailure,
|
||||
getFetchChangesetsFailure,
|
||||
isFetchChangesetPending,
|
||||
isFetchChangesetsPending,
|
||||
selectListAsCollection,
|
||||
shouldFetchChangeset,
|
||||
} from './changesets';
|
||||
|
||||
const branch = {
|
||||
name: 'specific',
|
||||
revision: '123',
|
||||
_links: {
|
||||
history: {
|
||||
href:
|
||||
'http://scm.hitchhicker.com/api/v2/repositories/foo/bar/branches/specific/changesets',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const repository = {
|
||||
namespace: 'foo',
|
||||
name: 'bar',
|
||||
type: 'GIT',
|
||||
_links: {
|
||||
self: {
|
||||
href: 'http://scm.hitchhicker.com/api/v2/repositories/foo/bar',
|
||||
},
|
||||
changesets: {
|
||||
href: 'http://scm.hitchhicker.com/api/v2/repositories/foo/bar/changesets',
|
||||
},
|
||||
branches: {
|
||||
href:
|
||||
'http://scm.hitchhicker.com/api/v2/repositories/foo/bar/branches/specific/branches',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const changesets = {};
|
||||
|
||||
describe('changesets', () => {
|
||||
describe('fetching of changesets', () => {
|
||||
const DEFAULT_BRANCH_URL =
|
||||
'http://scm.hitchhicker.com/api/v2/repositories/foo/bar/changesets';
|
||||
const SPECIFIC_BRANCH_URL =
|
||||
'http://scm.hitchhicker.com/api/v2/repositories/foo/bar/branches/specific/changesets';
|
||||
|
||||
const mockStore = configureMockStore([thunk]);
|
||||
|
||||
afterEach(() => {
|
||||
fetchMock.reset();
|
||||
fetchMock.restore();
|
||||
});
|
||||
|
||||
const changesetId = 'aba876c0625d90a6aff1494f3d161aaa7008b958';
|
||||
|
||||
it('should fetch changeset', () => {
|
||||
fetchMock.getOnce(DEFAULT_BRANCH_URL + '/' + changesetId, '{}');
|
||||
|
||||
const expectedActions = [
|
||||
{
|
||||
type: FETCH_CHANGESET_PENDING,
|
||||
itemId: 'foo/bar/' + changesetId,
|
||||
},
|
||||
{
|
||||
type: FETCH_CHANGESET_SUCCESS,
|
||||
payload: {
|
||||
changeset: {},
|
||||
id: changesetId,
|
||||
repository: repository,
|
||||
},
|
||||
itemId: 'foo/bar/' + changesetId,
|
||||
},
|
||||
];
|
||||
|
||||
const store = mockStore({});
|
||||
return store
|
||||
.dispatch(fetchChangeset(repository, changesetId))
|
||||
.then(() => {
|
||||
expect(store.getActions()).toEqual(expectedActions);
|
||||
});
|
||||
});
|
||||
|
||||
it('should fail fetching changeset on error', () => {
|
||||
fetchMock.getOnce(DEFAULT_BRANCH_URL + '/' + changesetId, 500);
|
||||
|
||||
const expectedActions = [
|
||||
{
|
||||
type: FETCH_CHANGESET_PENDING,
|
||||
itemId: 'foo/bar/' + changesetId,
|
||||
},
|
||||
];
|
||||
|
||||
const store = mockStore({});
|
||||
return store
|
||||
.dispatch(fetchChangeset(repository, changesetId))
|
||||
.then(() => {
|
||||
expect(store.getActions()[0]).toEqual(expectedActions[0]);
|
||||
expect(store.getActions()[1].type).toEqual(FETCH_CHANGESET_FAILURE);
|
||||
expect(store.getActions()[1].payload).toBeDefined();
|
||||
});
|
||||
});
|
||||
|
||||
it('should fetch changeset if needed', () => {
|
||||
fetchMock.getOnce(DEFAULT_BRANCH_URL + '/id3', '{}');
|
||||
|
||||
const expectedActions = [
|
||||
{
|
||||
type: FETCH_CHANGESET_PENDING,
|
||||
itemId: 'foo/bar/id3',
|
||||
},
|
||||
{
|
||||
type: FETCH_CHANGESET_SUCCESS,
|
||||
payload: {
|
||||
changeset: {},
|
||||
id: 'id3',
|
||||
repository: repository,
|
||||
},
|
||||
itemId: 'foo/bar/id3',
|
||||
},
|
||||
];
|
||||
|
||||
const store = mockStore({});
|
||||
return store
|
||||
.dispatch(fetchChangesetIfNeeded(repository, 'id3'))
|
||||
.then(() => {
|
||||
expect(store.getActions()).toEqual(expectedActions);
|
||||
});
|
||||
});
|
||||
|
||||
it('should not fetch changeset if not needed', () => {
|
||||
fetchMock.getOnce(DEFAULT_BRANCH_URL + '/id1', 500);
|
||||
|
||||
const state = {
|
||||
changesets: {
|
||||
'foo/bar': {
|
||||
byId: {
|
||||
id1: {
|
||||
id: 'id1',
|
||||
},
|
||||
id2: {
|
||||
id: 'id2',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const store = mockStore(state);
|
||||
return expect(
|
||||
store.dispatch(fetchChangesetIfNeeded(repository, 'id1')),
|
||||
).toEqual(undefined);
|
||||
});
|
||||
|
||||
it('should fetch changesets for default branch', () => {
|
||||
fetchMock.getOnce(DEFAULT_BRANCH_URL, '{}');
|
||||
|
||||
const expectedActions = [
|
||||
{
|
||||
type: FETCH_CHANGESETS_PENDING,
|
||||
itemId: 'foo/bar',
|
||||
},
|
||||
{
|
||||
type: FETCH_CHANGESETS_SUCCESS,
|
||||
payload: {
|
||||
repository,
|
||||
undefined,
|
||||
changesets,
|
||||
},
|
||||
itemId: 'foo/bar',
|
||||
},
|
||||
];
|
||||
|
||||
const store = mockStore({});
|
||||
return store.dispatch(fetchChangesets(repository)).then(() => {
|
||||
expect(store.getActions()).toEqual(expectedActions);
|
||||
});
|
||||
});
|
||||
|
||||
it('should fetch changesets for specific branch', () => {
|
||||
const itemId = 'foo/bar/specific';
|
||||
fetchMock.getOnce(SPECIFIC_BRANCH_URL, '{}');
|
||||
|
||||
const expectedActions = [
|
||||
{
|
||||
type: FETCH_CHANGESETS_PENDING,
|
||||
itemId,
|
||||
},
|
||||
{
|
||||
type: FETCH_CHANGESETS_SUCCESS,
|
||||
payload: {
|
||||
repository,
|
||||
branch,
|
||||
changesets,
|
||||
},
|
||||
itemId,
|
||||
},
|
||||
];
|
||||
|
||||
const store = mockStore({});
|
||||
return store.dispatch(fetchChangesets(repository, branch)).then(() => {
|
||||
expect(store.getActions()).toEqual(expectedActions);
|
||||
});
|
||||
});
|
||||
|
||||
it('should fail fetching changesets on error', () => {
|
||||
const itemId = 'foo/bar';
|
||||
fetchMock.getOnce(DEFAULT_BRANCH_URL, 500);
|
||||
|
||||
const expectedActions = [
|
||||
{
|
||||
type: FETCH_CHANGESETS_PENDING,
|
||||
itemId,
|
||||
},
|
||||
];
|
||||
|
||||
const store = mockStore({});
|
||||
return store.dispatch(fetchChangesets(repository)).then(() => {
|
||||
expect(store.getActions()[0]).toEqual(expectedActions[0]);
|
||||
expect(store.getActions()[1].type).toEqual(FETCH_CHANGESETS_FAILURE);
|
||||
expect(store.getActions()[1].payload).toBeDefined();
|
||||
});
|
||||
});
|
||||
|
||||
it('should fail fetching changesets for specific branch on error', () => {
|
||||
const itemId = 'foo/bar/specific';
|
||||
fetchMock.getOnce(SPECIFIC_BRANCH_URL, 500);
|
||||
|
||||
const expectedActions = [
|
||||
{
|
||||
type: FETCH_CHANGESETS_PENDING,
|
||||
itemId,
|
||||
},
|
||||
];
|
||||
|
||||
const store = mockStore({});
|
||||
return store.dispatch(fetchChangesets(repository, branch)).then(() => {
|
||||
expect(store.getActions()[0]).toEqual(expectedActions[0]);
|
||||
expect(store.getActions()[1].type).toEqual(FETCH_CHANGESETS_FAILURE);
|
||||
expect(store.getActions()[1].payload).toBeDefined();
|
||||
});
|
||||
});
|
||||
|
||||
it('should fetch changesets by page', () => {
|
||||
fetchMock.getOnce(DEFAULT_BRANCH_URL + '?page=4', '{}');
|
||||
|
||||
const expectedActions = [
|
||||
{
|
||||
type: FETCH_CHANGESETS_PENDING,
|
||||
itemId: 'foo/bar',
|
||||
},
|
||||
{
|
||||
type: FETCH_CHANGESETS_SUCCESS,
|
||||
payload: {
|
||||
repository,
|
||||
undefined,
|
||||
changesets,
|
||||
},
|
||||
itemId: 'foo/bar',
|
||||
},
|
||||
];
|
||||
|
||||
const store = mockStore({});
|
||||
return store
|
||||
.dispatch(fetchChangesets(repository, undefined, 5))
|
||||
.then(() => {
|
||||
expect(store.getActions()).toEqual(expectedActions);
|
||||
});
|
||||
});
|
||||
|
||||
it('should fetch changesets by branch and page', () => {
|
||||
fetchMock.getOnce(SPECIFIC_BRANCH_URL + '?page=4', '{}');
|
||||
|
||||
const expectedActions = [
|
||||
{
|
||||
type: FETCH_CHANGESETS_PENDING,
|
||||
itemId: 'foo/bar/specific',
|
||||
},
|
||||
{
|
||||
type: FETCH_CHANGESETS_SUCCESS,
|
||||
payload: {
|
||||
repository,
|
||||
branch,
|
||||
changesets,
|
||||
},
|
||||
itemId: 'foo/bar/specific',
|
||||
},
|
||||
];
|
||||
|
||||
const store = mockStore({});
|
||||
return store.dispatch(fetchChangesets(repository, branch, 5)).then(() => {
|
||||
expect(store.getActions()).toEqual(expectedActions);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('changesets reducer', () => {
|
||||
const responseBody = {
|
||||
page: 1,
|
||||
pageTotal: 10,
|
||||
_links: {},
|
||||
_embedded: {
|
||||
changesets: [
|
||||
{
|
||||
id: 'changeset1',
|
||||
author: {
|
||||
mail: 'z@phod.com',
|
||||
name: 'zaphod',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'changeset2',
|
||||
description: 'foo',
|
||||
},
|
||||
{
|
||||
id: 'changeset3',
|
||||
description: 'bar',
|
||||
},
|
||||
],
|
||||
_embedded: {
|
||||
tags: [],
|
||||
branches: [],
|
||||
parents: [],
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
it('should set state to received changesets', () => {
|
||||
const newState = reducer(
|
||||
{},
|
||||
fetchChangesetsSuccess(repository, undefined, responseBody),
|
||||
);
|
||||
expect(newState).toBeDefined();
|
||||
expect(newState['foo/bar'].byId['changeset1'].author.mail).toEqual(
|
||||
'z@phod.com',
|
||||
);
|
||||
expect(newState['foo/bar'].byId['changeset2'].description).toEqual('foo');
|
||||
expect(newState['foo/bar'].byId['changeset3'].description).toEqual('bar');
|
||||
expect(newState['foo/bar'].byBranch['']).toEqual({
|
||||
entry: {
|
||||
page: 1,
|
||||
pageTotal: 10,
|
||||
_links: {},
|
||||
},
|
||||
entries: ['changeset1', 'changeset2', 'changeset3'],
|
||||
});
|
||||
});
|
||||
|
||||
it('should store the changeset list to branch', () => {
|
||||
const newState = reducer(
|
||||
{},
|
||||
fetchChangesetsSuccess(repository, branch, responseBody),
|
||||
);
|
||||
|
||||
expect(newState['foo/bar'].byId['changeset1']).toBeDefined();
|
||||
expect(newState['foo/bar'].byBranch['specific'].entries).toEqual([
|
||||
'changeset1',
|
||||
'changeset2',
|
||||
'changeset3',
|
||||
]);
|
||||
});
|
||||
|
||||
it('should not remove existing changesets', () => {
|
||||
const state = {
|
||||
'foo/bar': {
|
||||
byId: {
|
||||
id2: {
|
||||
id: 'id2',
|
||||
},
|
||||
id1: {
|
||||
id: 'id1',
|
||||
},
|
||||
},
|
||||
byBranch: {
|
||||
'': {
|
||||
entries: ['id1', 'id2'],
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const newState = reducer(
|
||||
state,
|
||||
fetchChangesetsSuccess(repository, undefined, responseBody),
|
||||
);
|
||||
|
||||
const fooBar = newState['foo/bar'];
|
||||
|
||||
expect(fooBar.byBranch[''].entries).toEqual([
|
||||
'changeset1',
|
||||
'changeset2',
|
||||
'changeset3',
|
||||
]);
|
||||
expect(fooBar.byId['id2']).toEqual({
|
||||
id: 'id2',
|
||||
});
|
||||
expect(fooBar.byId['id1']).toEqual({
|
||||
id: 'id1',
|
||||
});
|
||||
});
|
||||
|
||||
const responseBodySingleChangeset = {
|
||||
id: 'id3',
|
||||
author: {
|
||||
mail: 'z@phod.com',
|
||||
name: 'zaphod',
|
||||
},
|
||||
date: '2018-09-13T08:46:22Z',
|
||||
description: 'added testChangeset',
|
||||
_links: {},
|
||||
_embedded: {
|
||||
tags: [],
|
||||
branches: [],
|
||||
},
|
||||
};
|
||||
|
||||
it('should add changeset to state', () => {
|
||||
const newState = reducer(
|
||||
{
|
||||
'foo/bar': {
|
||||
byId: {
|
||||
id2: {
|
||||
id: 'id2',
|
||||
author: {
|
||||
mail: 'mail@author.com',
|
||||
name: 'author',
|
||||
},
|
||||
},
|
||||
},
|
||||
list: {
|
||||
entry: {
|
||||
page: 1,
|
||||
pageTotal: 10,
|
||||
_links: {},
|
||||
},
|
||||
entries: ['id2'],
|
||||
},
|
||||
},
|
||||
},
|
||||
fetchChangesetSuccess(responseBodySingleChangeset, repository, 'id3'),
|
||||
);
|
||||
|
||||
expect(newState).toBeDefined();
|
||||
expect(newState['foo/bar'].byId['id3'].description).toEqual(
|
||||
'added testChangeset',
|
||||
);
|
||||
expect(newState['foo/bar'].byId['id3'].author.mail).toEqual('z@phod.com');
|
||||
expect(newState['foo/bar'].byId['id2']).toBeDefined();
|
||||
expect(newState['foo/bar'].byId['id3']).toBeDefined();
|
||||
expect(newState['foo/bar'].list).toEqual({
|
||||
entry: {
|
||||
page: 1,
|
||||
pageTotal: 10,
|
||||
_links: {},
|
||||
},
|
||||
entries: ['id2'],
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('changeset selectors', () => {
|
||||
const error = new Error('Something went wrong');
|
||||
|
||||
it('should return changeset', () => {
|
||||
const state = {
|
||||
changesets: {
|
||||
'foo/bar': {
|
||||
byId: {
|
||||
id1: {
|
||||
id: 'id1',
|
||||
},
|
||||
id2: {
|
||||
id: 'id2',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
const result = getChangeset(state, repository, 'id1');
|
||||
expect(result).toEqual({
|
||||
id: 'id1',
|
||||
});
|
||||
});
|
||||
|
||||
it('should return null if changeset does not exist', () => {
|
||||
const state = {
|
||||
changesets: {
|
||||
'foo/bar': {
|
||||
byId: {
|
||||
id1: {
|
||||
id: 'id1',
|
||||
},
|
||||
id2: {
|
||||
id: 'id2',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
const result = getChangeset(state, repository, 'id3');
|
||||
expect(result).toEqual(null);
|
||||
});
|
||||
|
||||
it('should return true if changeset does not exist', () => {
|
||||
const state = {
|
||||
changesets: {
|
||||
'foo/bar': {
|
||||
byId: {
|
||||
id1: {
|
||||
id: 'id1',
|
||||
},
|
||||
id2: {
|
||||
id: 'id2',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
const result = shouldFetchChangeset(state, repository, 'id3');
|
||||
expect(result).toEqual(true);
|
||||
});
|
||||
|
||||
it('should return false if changeset exists', () => {
|
||||
const state = {
|
||||
changesets: {
|
||||
'foo/bar': {
|
||||
byId: {
|
||||
id1: {
|
||||
id: 'id1',
|
||||
},
|
||||
id2: {
|
||||
id: 'id2',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
const result = shouldFetchChangeset(state, repository, 'id2');
|
||||
expect(result).toEqual(false);
|
||||
});
|
||||
|
||||
it('should return true, when fetching changeset is pending', () => {
|
||||
const state = {
|
||||
pending: {
|
||||
[FETCH_CHANGESET + '/foo/bar/id1']: true,
|
||||
},
|
||||
};
|
||||
|
||||
expect(isFetchChangesetPending(state, repository, 'id1')).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should return false, when fetching changeset is not pending', () => {
|
||||
expect(isFetchChangesetPending({}, repository, 'id1')).toEqual(false);
|
||||
});
|
||||
|
||||
it('should return error if fetching changeset failed', () => {
|
||||
const state = {
|
||||
failure: {
|
||||
[FETCH_CHANGESET + '/foo/bar/id1']: error,
|
||||
},
|
||||
};
|
||||
|
||||
expect(getFetchChangesetFailure(state, repository, 'id1')).toEqual(error);
|
||||
});
|
||||
|
||||
it('should return false if fetching changeset did not fail', () => {
|
||||
expect(getFetchChangesetFailure({}, repository, 'id1')).toBeUndefined();
|
||||
});
|
||||
|
||||
it('should get all changesets for a given repository', () => {
|
||||
const state = {
|
||||
changesets: {
|
||||
'foo/bar': {
|
||||
byId: {
|
||||
id2: {
|
||||
id: 'id2',
|
||||
},
|
||||
id1: {
|
||||
id: 'id1',
|
||||
},
|
||||
},
|
||||
byBranch: {
|
||||
'': {
|
||||
entries: ['id1', 'id2'],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
const result = getChangesets(state, repository);
|
||||
expect(result).toEqual([
|
||||
{
|
||||
id: 'id1',
|
||||
},
|
||||
{
|
||||
id: 'id2',
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
it('should return true, when fetching changesets is pending', () => {
|
||||
const state = {
|
||||
pending: {
|
||||
[FETCH_CHANGESETS + '/foo/bar']: true,
|
||||
},
|
||||
};
|
||||
|
||||
expect(isFetchChangesetsPending(state, repository)).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should return false, when fetching changesets is not pending', () => {
|
||||
expect(isFetchChangesetsPending({}, repository)).toEqual(false);
|
||||
});
|
||||
|
||||
it('should return error if fetching changesets failed', () => {
|
||||
const state = {
|
||||
failure: {
|
||||
[FETCH_CHANGESETS + '/foo/bar']: error,
|
||||
},
|
||||
};
|
||||
|
||||
expect(getFetchChangesetsFailure(state, repository)).toEqual(error);
|
||||
});
|
||||
|
||||
it('should return false if fetching changesets did not fail', () => {
|
||||
expect(getFetchChangesetsFailure({}, repository)).toBeUndefined();
|
||||
});
|
||||
|
||||
it('should return list as collection for the default branch', () => {
|
||||
const state = {
|
||||
changesets: {
|
||||
'foo/bar': {
|
||||
byId: {
|
||||
id2: {
|
||||
id: 'id2',
|
||||
},
|
||||
id1: {
|
||||
id: 'id1',
|
||||
},
|
||||
},
|
||||
byBranch: {
|
||||
'': {
|
||||
entry: {
|
||||
page: 1,
|
||||
pageTotal: 10,
|
||||
_links: {},
|
||||
},
|
||||
entries: ['id1', 'id2'],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const collection = selectListAsCollection(state, repository);
|
||||
expect(collection.page).toBe(1);
|
||||
expect(collection.pageTotal).toBe(10);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,26 +1,24 @@
|
||||
// @flow
|
||||
|
||||
import {
|
||||
FAILURE_SUFFIX,
|
||||
PENDING_SUFFIX,
|
||||
SUCCESS_SUFFIX
|
||||
} from "../../modules/types";
|
||||
import { apiClient, urls } from "@scm-manager/ui-components";
|
||||
import { isPending } from "../../modules/pending";
|
||||
import { getFailure } from "../../modules/failure";
|
||||
import type {
|
||||
SUCCESS_SUFFIX,
|
||||
} from '../../modules/types';
|
||||
import { apiClient, urls } from '@scm-manager/ui-components';
|
||||
import { isPending } from '../../modules/pending';
|
||||
import { getFailure } from '../../modules/failure';
|
||||
import {
|
||||
Action,
|
||||
Branch,
|
||||
PagedCollection,
|
||||
Repository
|
||||
} from "@scm-manager/ui-types";
|
||||
Repository,
|
||||
} from '@scm-manager/ui-types';
|
||||
|
||||
export const FETCH_CHANGESETS = "scm/repos/FETCH_CHANGESETS";
|
||||
export const FETCH_CHANGESETS = 'scm/repos/FETCH_CHANGESETS';
|
||||
export const FETCH_CHANGESETS_PENDING = `${FETCH_CHANGESETS}_${PENDING_SUFFIX}`;
|
||||
export const FETCH_CHANGESETS_SUCCESS = `${FETCH_CHANGESETS}_${SUCCESS_SUFFIX}`;
|
||||
export const FETCH_CHANGESETS_FAILURE = `${FETCH_CHANGESETS}_${FAILURE_SUFFIX}`;
|
||||
|
||||
export const FETCH_CHANGESET = "scm/repos/FETCH_CHANGESET";
|
||||
export const FETCH_CHANGESET = 'scm/repos/FETCH_CHANGESET';
|
||||
export const FETCH_CHANGESET_PENDING = `${FETCH_CHANGESET}_${PENDING_SUFFIX}`;
|
||||
export const FETCH_CHANGESET_SUCCESS = `${FETCH_CHANGESET}_${SUCCESS_SUFFIX}`;
|
||||
export const FETCH_CHANGESET_FAILURE = `${FETCH_CHANGESET}_${FAILURE_SUFFIX}`;
|
||||
@@ -55,46 +53,50 @@ function createChangesetUrl(repository: Repository, id: string) {
|
||||
|
||||
export function fetchChangesetPending(
|
||||
repository: Repository,
|
||||
id: string
|
||||
id: string,
|
||||
): Action {
|
||||
return {
|
||||
type: FETCH_CHANGESET_PENDING,
|
||||
itemId: createChangesetItemId(repository, id)
|
||||
itemId: createChangesetItemId(repository, id),
|
||||
};
|
||||
}
|
||||
|
||||
export function fetchChangesetSuccess(
|
||||
changeset: any,
|
||||
repository: Repository,
|
||||
id: string
|
||||
id: string,
|
||||
): Action {
|
||||
return {
|
||||
type: FETCH_CHANGESET_SUCCESS,
|
||||
payload: { changeset, repository, id },
|
||||
itemId: createChangesetItemId(repository, id)
|
||||
payload: {
|
||||
changeset,
|
||||
repository,
|
||||
id,
|
||||
},
|
||||
itemId: createChangesetItemId(repository, id),
|
||||
};
|
||||
}
|
||||
|
||||
function fetchChangesetFailure(
|
||||
repository: Repository,
|
||||
id: string,
|
||||
error: Error
|
||||
error: Error,
|
||||
): Action {
|
||||
return {
|
||||
type: FETCH_CHANGESET_FAILURE,
|
||||
payload: {
|
||||
repository,
|
||||
id,
|
||||
error
|
||||
error,
|
||||
},
|
||||
itemId: createChangesetItemId(repository, id)
|
||||
itemId: createChangesetItemId(repository, id),
|
||||
};
|
||||
}
|
||||
|
||||
export function fetchChangesets(
|
||||
repository: Repository,
|
||||
branch?: Branch,
|
||||
page?: number
|
||||
page?: number,
|
||||
) {
|
||||
const link = createChangesetsLink(repository, branch, page);
|
||||
|
||||
@@ -115,7 +117,7 @@ export function fetchChangesets(
|
||||
function createChangesetsLink(
|
||||
repository: Repository,
|
||||
branch?: Branch,
|
||||
page?: number
|
||||
page?: number,
|
||||
) {
|
||||
let link = repository._links.changesets.href;
|
||||
|
||||
@@ -131,58 +133,58 @@ function createChangesetsLink(
|
||||
|
||||
export function fetchChangesetsPending(
|
||||
repository: Repository,
|
||||
branch?: Branch
|
||||
branch?: Branch,
|
||||
): Action {
|
||||
const itemId = createItemId(repository, branch);
|
||||
|
||||
return {
|
||||
type: FETCH_CHANGESETS_PENDING,
|
||||
itemId
|
||||
itemId,
|
||||
};
|
||||
}
|
||||
|
||||
export function fetchChangesetsSuccess(
|
||||
repository: Repository,
|
||||
branch?: Branch,
|
||||
changesets: any
|
||||
changesets: any,
|
||||
): Action {
|
||||
return {
|
||||
type: FETCH_CHANGESETS_SUCCESS,
|
||||
payload: {
|
||||
repository,
|
||||
branch,
|
||||
changesets
|
||||
changesets,
|
||||
},
|
||||
itemId: createItemId(repository, branch)
|
||||
itemId: createItemId(repository, branch),
|
||||
};
|
||||
}
|
||||
|
||||
function fetchChangesetsFailure(
|
||||
repository: Repository,
|
||||
branch?: Branch,
|
||||
error: Error
|
||||
error: Error,
|
||||
): Action {
|
||||
return {
|
||||
type: FETCH_CHANGESETS_FAILURE,
|
||||
payload: {
|
||||
repository,
|
||||
error,
|
||||
branch
|
||||
branch,
|
||||
},
|
||||
itemId: createItemId(repository, branch)
|
||||
itemId: createItemId(repository, branch),
|
||||
};
|
||||
}
|
||||
|
||||
function createChangesetItemId(repository: Repository, id: string) {
|
||||
const { namespace, name } = repository;
|
||||
return namespace + "/" + name + "/" + id;
|
||||
return namespace + '/' + name + '/' + id;
|
||||
}
|
||||
|
||||
function createItemId(repository: Repository, branch?: Branch): string {
|
||||
const { namespace, name } = repository;
|
||||
let itemId = namespace + "/" + name;
|
||||
let itemId = namespace + '/' + name;
|
||||
if (branch) {
|
||||
itemId = itemId + "/" + branch.name;
|
||||
itemId = itemId + '/' + branch.name;
|
||||
}
|
||||
return itemId;
|
||||
}
|
||||
@@ -190,8 +192,10 @@ function createItemId(repository: Repository, branch?: Branch): string {
|
||||
// reducer
|
||||
export default function reducer(
|
||||
state: any = {},
|
||||
action: Action = { type: "UNKNOWN" }
|
||||
): Object {
|
||||
action: Action = {
|
||||
type: 'UNKNOWN',
|
||||
},
|
||||
): object {
|
||||
if (!action.payload) {
|
||||
return state;
|
||||
}
|
||||
@@ -214,9 +218,9 @@ export default function reducer(
|
||||
...state[_key],
|
||||
byId: {
|
||||
..._oldByIds,
|
||||
[changeset.id]: changeset
|
||||
}
|
||||
}
|
||||
[changeset.id]: changeset,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
case FETCH_CHANGESETS_SUCCESS:
|
||||
@@ -235,7 +239,7 @@ export default function reducer(
|
||||
oldState = state[repoId];
|
||||
}
|
||||
|
||||
const branchName = payload.branch ? payload.branch.name : "";
|
||||
const branchName = payload.branch ? payload.branch.name : '';
|
||||
const byIds = extractChangesetsByIds(changesets);
|
||||
|
||||
return {
|
||||
@@ -243,7 +247,7 @@ export default function reducer(
|
||||
[repoId]: {
|
||||
byId: {
|
||||
...oldState.byId,
|
||||
...byIds
|
||||
...byIds,
|
||||
},
|
||||
byBranch: {
|
||||
...oldState.byBranch,
|
||||
@@ -252,11 +256,11 @@ export default function reducer(
|
||||
entry: {
|
||||
page: payload.changesets.page,
|
||||
pageTotal: payload.changesets.pageTotal,
|
||||
_links: payload.changesets._links
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
_links: payload.changesets._links,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
default:
|
||||
return state;
|
||||
@@ -275,9 +279,9 @@ function extractChangesetsByIds(changesets: any) {
|
||||
|
||||
//selectors
|
||||
export function getChangesets(
|
||||
state: Object,
|
||||
state: object,
|
||||
repository: Repository,
|
||||
branch?: Branch
|
||||
branch?: Branch,
|
||||
) {
|
||||
const repoKey = createItemId(repository);
|
||||
|
||||
@@ -286,7 +290,7 @@ export function getChangesets(
|
||||
return null;
|
||||
}
|
||||
|
||||
const branchName = branch ? branch.name : "";
|
||||
const branchName = branch ? branch.name : '';
|
||||
|
||||
const changesets = stateRoot.byBranch[branchName];
|
||||
if (!changesets) {
|
||||
@@ -299,9 +303,9 @@ export function getChangesets(
|
||||
}
|
||||
|
||||
export function getChangeset(
|
||||
state: Object,
|
||||
state: object,
|
||||
repository: Repository,
|
||||
id: string
|
||||
id: string,
|
||||
) {
|
||||
const key = createItemId(repository);
|
||||
const changesets =
|
||||
@@ -315,9 +319,9 @@ export function getChangeset(
|
||||
}
|
||||
|
||||
export function shouldFetchChangeset(
|
||||
state: Object,
|
||||
state: object,
|
||||
repository: Repository,
|
||||
id: string
|
||||
id: string,
|
||||
) {
|
||||
if (getChangeset(state, repository, id)) {
|
||||
return false;
|
||||
@@ -326,49 +330,49 @@ export function shouldFetchChangeset(
|
||||
}
|
||||
|
||||
export function isFetchChangesetPending(
|
||||
state: Object,
|
||||
state: object,
|
||||
repository: Repository,
|
||||
id: string
|
||||
id: string,
|
||||
) {
|
||||
return isPending(
|
||||
state,
|
||||
FETCH_CHANGESET,
|
||||
createChangesetItemId(repository, id)
|
||||
createChangesetItemId(repository, id),
|
||||
);
|
||||
}
|
||||
|
||||
export function getFetchChangesetFailure(
|
||||
state: Object,
|
||||
state: object,
|
||||
repository: Repository,
|
||||
id: string
|
||||
id: string,
|
||||
) {
|
||||
return getFailure(
|
||||
state,
|
||||
FETCH_CHANGESET,
|
||||
createChangesetItemId(repository, id)
|
||||
createChangesetItemId(repository, id),
|
||||
);
|
||||
}
|
||||
|
||||
export function isFetchChangesetsPending(
|
||||
state: Object,
|
||||
state: object,
|
||||
repository: Repository,
|
||||
branch?: Branch
|
||||
branch?: Branch,
|
||||
) {
|
||||
return isPending(state, FETCH_CHANGESETS, createItemId(repository, branch));
|
||||
}
|
||||
|
||||
export function getFetchChangesetsFailure(
|
||||
state: Object,
|
||||
state: object,
|
||||
repository: Repository,
|
||||
branch?: Branch
|
||||
branch?: Branch,
|
||||
) {
|
||||
return getFailure(state, FETCH_CHANGESETS, createItemId(repository, branch));
|
||||
}
|
||||
|
||||
const selectList = (state: Object, repository: Repository, branch?: Branch) => {
|
||||
const selectList = (state: object, repository: Repository, branch?: Branch) => {
|
||||
const repoId = createItemId(repository);
|
||||
|
||||
const branchName = branch ? branch.name : "";
|
||||
const branchName = branch ? branch.name : '';
|
||||
if (state.changesets[repoId]) {
|
||||
const repoState = state.changesets[repoId];
|
||||
|
||||
@@ -380,10 +384,10 @@ const selectList = (state: Object, repository: Repository, branch?: Branch) => {
|
||||
};
|
||||
|
||||
const selectListEntry = (
|
||||
state: Object,
|
||||
state: object,
|
||||
repository: Repository,
|
||||
branch?: Branch
|
||||
): Object => {
|
||||
branch?: Branch,
|
||||
): object => {
|
||||
const list = selectList(state, repository, branch);
|
||||
if (list.entry) {
|
||||
return list.entry;
|
||||
@@ -392,9 +396,9 @@ const selectListEntry = (
|
||||
};
|
||||
|
||||
export const selectListAsCollection = (
|
||||
state: Object,
|
||||
state: object,
|
||||
repository: Repository,
|
||||
branch?: Branch
|
||||
branch?: Branch,
|
||||
): PagedCollection => {
|
||||
return selectListEntry(state, repository, branch);
|
||||
};
|
||||
@@ -1,858 +0,0 @@
|
||||
// @flow
|
||||
import configureMockStore from "redux-mock-store";
|
||||
import thunk from "redux-thunk";
|
||||
import fetchMock from "fetch-mock";
|
||||
import reducer, {
|
||||
FETCH_REPOS_PENDING,
|
||||
FETCH_REPOS_SUCCESS,
|
||||
fetchRepos,
|
||||
FETCH_REPOS_FAILURE,
|
||||
fetchReposSuccess,
|
||||
getRepositoryCollection,
|
||||
FETCH_REPOS,
|
||||
isFetchReposPending,
|
||||
getFetchReposFailure,
|
||||
fetchReposByLink,
|
||||
fetchReposByPage,
|
||||
FETCH_REPO,
|
||||
fetchRepoByLink,
|
||||
fetchRepoByName,
|
||||
FETCH_REPO_PENDING,
|
||||
FETCH_REPO_SUCCESS,
|
||||
FETCH_REPO_FAILURE,
|
||||
fetchRepoSuccess,
|
||||
getRepository,
|
||||
isFetchRepoPending,
|
||||
getFetchRepoFailure,
|
||||
CREATE_REPO_PENDING,
|
||||
CREATE_REPO_SUCCESS,
|
||||
createRepo,
|
||||
CREATE_REPO_FAILURE,
|
||||
isCreateRepoPending,
|
||||
CREATE_REPO,
|
||||
getCreateRepoFailure,
|
||||
isAbleToCreateRepos,
|
||||
DELETE_REPO,
|
||||
DELETE_REPO_SUCCESS,
|
||||
deleteRepo,
|
||||
DELETE_REPO_PENDING,
|
||||
DELETE_REPO_FAILURE,
|
||||
isDeleteRepoPending,
|
||||
getDeleteRepoFailure,
|
||||
modifyRepo,
|
||||
MODIFY_REPO_PENDING,
|
||||
MODIFY_REPO_SUCCESS,
|
||||
MODIFY_REPO_FAILURE,
|
||||
MODIFY_REPO,
|
||||
isModifyRepoPending,
|
||||
getModifyRepoFailure,
|
||||
getPermissionsLink
|
||||
} from "./repos";
|
||||
import type { Repository, RepositoryCollection } from "@scm-manager/ui-types";
|
||||
|
||||
const hitchhikerPuzzle42: Repository = {
|
||||
contact: "fourtytwo@hitchhiker.com",
|
||||
creationDate: "2018-07-31T08:58:45.961Z",
|
||||
description: "the answer to life the universe and everything",
|
||||
namespace: "hitchhiker",
|
||||
name: "puzzle42",
|
||||
type: "svn",
|
||||
_links: {
|
||||
self: {
|
||||
href: "http://localhost:8081/api/v2/repositories/hitchhiker/puzzle42"
|
||||
},
|
||||
delete: {
|
||||
href: "http://localhost:8081/api/v2/repositories/hitchhiker/puzzle42"
|
||||
},
|
||||
update: {
|
||||
href: "http://localhost:8081/api/v2/repositories/hitchhiker/puzzle42"
|
||||
},
|
||||
permissions: {
|
||||
href:
|
||||
"http://localhost:8081/api/v2/repositories/hitchhiker/puzzle42/permissions/"
|
||||
},
|
||||
tags: {
|
||||
href:
|
||||
"http://localhost:8081/api/v2/repositories/hitchhiker/puzzle42/tags/"
|
||||
},
|
||||
branches: {
|
||||
href:
|
||||
"http://localhost:8081/api/v2/repositories/hitchhiker/puzzle42/branches/"
|
||||
},
|
||||
changesets: {
|
||||
href:
|
||||
"http://localhost:8081/api/v2/repositories/hitchhiker/puzzle42/changesets/"
|
||||
},
|
||||
sources: {
|
||||
href:
|
||||
"http://localhost:8081/api/v2/repositories/hitchhiker/puzzle42/sources/"
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const hitchhikerRestatend: Repository = {
|
||||
contact: "restatend@hitchhiker.com",
|
||||
creationDate: "2018-07-31T08:58:32.803Z",
|
||||
description: "restaurant at the end of the universe",
|
||||
namespace: "hitchhiker",
|
||||
name: "restatend",
|
||||
type: "git",
|
||||
_links: {
|
||||
self: {
|
||||
href: "http://localhost:8081/api/v2/repositories/hitchhiker/restatend"
|
||||
},
|
||||
delete: {
|
||||
href: "http://localhost:8081/api/v2/repositories/hitchhiker/restatend"
|
||||
},
|
||||
update: {
|
||||
href: "http://localhost:8081/api/v2/repositories/hitchhiker/restatend"
|
||||
},
|
||||
permissions: {
|
||||
href:
|
||||
"http://localhost:8081/api/v2/repositories/hitchhiker/restatend/permissions/"
|
||||
},
|
||||
tags: {
|
||||
href:
|
||||
"http://localhost:8081/api/v2/repositories/hitchhiker/restatend/tags/"
|
||||
},
|
||||
branches: {
|
||||
href:
|
||||
"http://localhost:8081/api/v2/repositories/hitchhiker/restatend/branches/"
|
||||
},
|
||||
changesets: {
|
||||
href:
|
||||
"http://localhost:8081/api/v2/repositories/hitchhiker/restatend/changesets/"
|
||||
},
|
||||
sources: {
|
||||
href:
|
||||
"http://localhost:8081/api/v2/repositories/hitchhiker/restatend/sources/"
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const slartiFjords: Repository = {
|
||||
contact: "slartibartfast@hitchhiker.com",
|
||||
description: "My award-winning fjords from the Norwegian coast",
|
||||
namespace: "slarti",
|
||||
name: "fjords",
|
||||
type: "hg",
|
||||
creationDate: "2018-07-31T08:59:05.653Z",
|
||||
_links: {
|
||||
self: {
|
||||
href: "http://localhost:8081/api/v2/repositories/slarti/fjords"
|
||||
},
|
||||
delete: {
|
||||
href: "http://localhost:8081/api/v2/repositories/slarti/fjords"
|
||||
},
|
||||
update: {
|
||||
href: "http://localhost:8081/api/v2/repositories/slarti/fjords"
|
||||
},
|
||||
permissions: {
|
||||
href:
|
||||
"http://localhost:8081/api/v2/repositories/slarti/fjords/permissions/"
|
||||
},
|
||||
tags: {
|
||||
href: "http://localhost:8081/api/v2/repositories/slarti/fjords/tags/"
|
||||
},
|
||||
branches: {
|
||||
href: "http://localhost:8081/api/v2/repositories/slarti/fjords/branches/"
|
||||
},
|
||||
changesets: {
|
||||
href:
|
||||
"http://localhost:8081/api/v2/repositories/slarti/fjords/changesets/"
|
||||
},
|
||||
sources: {
|
||||
href: "http://localhost:8081/api/v2/repositories/slarti/fjords/sources/"
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const repositoryCollection: RepositoryCollection = {
|
||||
page: 0,
|
||||
pageTotal: 1,
|
||||
_links: {
|
||||
self: {
|
||||
href: "http://localhost:8081/api/v2/repositories/?page=0&pageSize=10"
|
||||
},
|
||||
first: {
|
||||
href: "http://localhost:8081/api/v2/repositories/?page=0&pageSize=10"
|
||||
},
|
||||
last: {
|
||||
href: "http://localhost:8081/api/v2/repositories/?page=0&pageSize=10"
|
||||
},
|
||||
create: {
|
||||
href: "http://localhost:8081/api/v2/repositories/"
|
||||
}
|
||||
},
|
||||
_embedded: {
|
||||
repositories: [hitchhikerPuzzle42, hitchhikerRestatend, slartiFjords]
|
||||
}
|
||||
};
|
||||
|
||||
const repositoryCollectionWithNames: RepositoryCollection = {
|
||||
page: 0,
|
||||
pageTotal: 1,
|
||||
_links: {
|
||||
self: {
|
||||
href: "http://localhost:8081/api/v2/repositories/?page=0&pageSize=10"
|
||||
},
|
||||
first: {
|
||||
href: "http://localhost:8081/api/v2/repositories/?page=0&pageSize=10"
|
||||
},
|
||||
last: {
|
||||
href: "http://localhost:8081/api/v2/repositories/?page=0&pageSize=10"
|
||||
},
|
||||
create: {
|
||||
href: "http://localhost:8081/api/v2/repositories/"
|
||||
}
|
||||
},
|
||||
_embedded: {
|
||||
repositories: [
|
||||
"hitchhiker/puzzle42",
|
||||
"hitchhiker/restatend",
|
||||
"slarti/fjords"
|
||||
]
|
||||
}
|
||||
};
|
||||
|
||||
describe("repos fetch", () => {
|
||||
const URL = "repositories";
|
||||
const REPOS_URL = "/api/v2/repositories";
|
||||
const SORT = "sortBy=namespaceAndName";
|
||||
const REPOS_URL_WITH_SORT = REPOS_URL + "?" + SORT;
|
||||
const mockStore = configureMockStore([thunk]);
|
||||
|
||||
afterEach(() => {
|
||||
fetchMock.reset();
|
||||
fetchMock.restore();
|
||||
});
|
||||
|
||||
it("should successfully fetch repos", () => {
|
||||
fetchMock.getOnce(REPOS_URL_WITH_SORT, repositoryCollection);
|
||||
|
||||
const expectedActions = [
|
||||
{ type: FETCH_REPOS_PENDING },
|
||||
{
|
||||
type: FETCH_REPOS_SUCCESS,
|
||||
payload: repositoryCollection
|
||||
}
|
||||
];
|
||||
|
||||
const store = mockStore({});
|
||||
return store.dispatch(fetchRepos(URL)).then(() => {
|
||||
expect(store.getActions()).toEqual(expectedActions);
|
||||
});
|
||||
});
|
||||
|
||||
it("should successfully fetch page 42", () => {
|
||||
const url = REPOS_URL + "?page=42&" + SORT;
|
||||
fetchMock.getOnce(url, repositoryCollection);
|
||||
|
||||
const expectedActions = [
|
||||
{ type: FETCH_REPOS_PENDING },
|
||||
{
|
||||
type: FETCH_REPOS_SUCCESS,
|
||||
payload: repositoryCollection
|
||||
}
|
||||
];
|
||||
|
||||
const store = mockStore({});
|
||||
|
||||
return store.dispatch(fetchReposByPage(URL, 43)).then(() => {
|
||||
expect(store.getActions()).toEqual(expectedActions);
|
||||
});
|
||||
});
|
||||
|
||||
it("should successfully fetch repos from link", () => {
|
||||
fetchMock.getOnce(
|
||||
REPOS_URL + "?" + SORT + "&page=42",
|
||||
repositoryCollection
|
||||
);
|
||||
|
||||
const expectedActions = [
|
||||
{ type: FETCH_REPOS_PENDING },
|
||||
{
|
||||
type: FETCH_REPOS_SUCCESS,
|
||||
payload: repositoryCollection
|
||||
}
|
||||
];
|
||||
|
||||
const store = mockStore({});
|
||||
return store
|
||||
.dispatch(
|
||||
fetchReposByLink("/repositories?sortBy=namespaceAndName&page=42")
|
||||
)
|
||||
.then(() => {
|
||||
expect(store.getActions()).toEqual(expectedActions);
|
||||
});
|
||||
});
|
||||
|
||||
it("should append sortby parameter and successfully fetch repos from link", () => {
|
||||
fetchMock.getOnce(
|
||||
"/api/v2/repositories?one=1&sortBy=namespaceAndName",
|
||||
repositoryCollection
|
||||
);
|
||||
|
||||
const expectedActions = [
|
||||
{ type: FETCH_REPOS_PENDING },
|
||||
{
|
||||
type: FETCH_REPOS_SUCCESS,
|
||||
payload: repositoryCollection
|
||||
}
|
||||
];
|
||||
|
||||
const store = mockStore({});
|
||||
|
||||
return store.dispatch(fetchReposByLink("/repositories?one=1")).then(() => {
|
||||
expect(store.getActions()).toEqual(expectedActions);
|
||||
});
|
||||
});
|
||||
|
||||
it("should dispatch FETCH_REPOS_FAILURE, it the request fails", () => {
|
||||
fetchMock.getOnce(REPOS_URL_WITH_SORT, {
|
||||
status: 500
|
||||
});
|
||||
|
||||
const store = mockStore({});
|
||||
return store.dispatch(fetchRepos(URL)).then(() => {
|
||||
const actions = store.getActions();
|
||||
expect(actions[0].type).toEqual(FETCH_REPOS_PENDING);
|
||||
expect(actions[1].type).toEqual(FETCH_REPOS_FAILURE);
|
||||
expect(actions[1].payload).toBeDefined();
|
||||
});
|
||||
});
|
||||
|
||||
it("should successfully fetch repo slarti/fjords by name", () => {
|
||||
fetchMock.getOnce(REPOS_URL + "/slarti/fjords", slartiFjords);
|
||||
|
||||
const expectedActions = [
|
||||
{
|
||||
type: FETCH_REPO_PENDING,
|
||||
payload: {
|
||||
namespace: "slarti",
|
||||
name: "fjords"
|
||||
},
|
||||
itemId: "slarti/fjords"
|
||||
},
|
||||
{
|
||||
type: FETCH_REPO_SUCCESS,
|
||||
payload: slartiFjords,
|
||||
itemId: "slarti/fjords"
|
||||
}
|
||||
];
|
||||
|
||||
const store = mockStore({});
|
||||
return store.dispatch(fetchRepoByName(URL, "slarti", "fjords")).then(() => {
|
||||
expect(store.getActions()).toEqual(expectedActions);
|
||||
});
|
||||
});
|
||||
|
||||
it("should dispatch FETCH_REPO_FAILURE, if the request for slarti/fjords by name fails", () => {
|
||||
fetchMock.getOnce(REPOS_URL + "/slarti/fjords", {
|
||||
status: 500
|
||||
});
|
||||
|
||||
const store = mockStore({});
|
||||
return store.dispatch(fetchRepoByName(URL, "slarti", "fjords")).then(() => {
|
||||
const actions = store.getActions();
|
||||
expect(actions[0].type).toEqual(FETCH_REPO_PENDING);
|
||||
expect(actions[1].type).toEqual(FETCH_REPO_FAILURE);
|
||||
expect(actions[1].payload.namespace).toBe("slarti");
|
||||
expect(actions[1].payload.name).toBe("fjords");
|
||||
expect(actions[1].payload.error).toBeDefined();
|
||||
expect(actions[1].itemId).toBe("slarti/fjords");
|
||||
});
|
||||
});
|
||||
|
||||
it("should successfully fetch repo slarti/fjords", () => {
|
||||
fetchMock.getOnce(
|
||||
"http://localhost:8081/api/v2/repositories/slarti/fjords",
|
||||
slartiFjords
|
||||
);
|
||||
|
||||
const expectedActions = [
|
||||
{
|
||||
type: FETCH_REPO_PENDING,
|
||||
payload: {
|
||||
namespace: "slarti",
|
||||
name: "fjords"
|
||||
},
|
||||
itemId: "slarti/fjords"
|
||||
},
|
||||
{
|
||||
type: FETCH_REPO_SUCCESS,
|
||||
payload: slartiFjords,
|
||||
itemId: "slarti/fjords"
|
||||
}
|
||||
];
|
||||
|
||||
const store = mockStore({});
|
||||
return store.dispatch(fetchRepoByLink(slartiFjords)).then(() => {
|
||||
expect(store.getActions()).toEqual(expectedActions);
|
||||
});
|
||||
});
|
||||
|
||||
it("should dispatch FETCH_REPO_FAILURE, it the request for slarti/fjords fails", () => {
|
||||
fetchMock.getOnce(
|
||||
"http://localhost:8081/api/v2/repositories/slarti/fjords",
|
||||
{
|
||||
status: 500
|
||||
}
|
||||
);
|
||||
|
||||
const store = mockStore({});
|
||||
return store.dispatch(fetchRepoByLink(slartiFjords)).then(() => {
|
||||
const actions = store.getActions();
|
||||
expect(actions[0].type).toEqual(FETCH_REPO_PENDING);
|
||||
expect(actions[1].type).toEqual(FETCH_REPO_FAILURE);
|
||||
expect(actions[1].payload.namespace).toBe("slarti");
|
||||
expect(actions[1].payload.name).toBe("fjords");
|
||||
expect(actions[1].payload.error).toBeDefined();
|
||||
expect(actions[1].itemId).toBe("slarti/fjords");
|
||||
});
|
||||
});
|
||||
|
||||
it("should successfully create repo slarti/fjords", () => {
|
||||
fetchMock.postOnce(REPOS_URL, {
|
||||
status: 201,
|
||||
headers: {
|
||||
location: "repositories/slarti/fjords"
|
||||
}
|
||||
});
|
||||
|
||||
fetchMock.getOnce(REPOS_URL + "/slarti/fjords", slartiFjords);
|
||||
|
||||
const expectedActions = [
|
||||
{
|
||||
type: CREATE_REPO_PENDING
|
||||
},
|
||||
{
|
||||
type: CREATE_REPO_SUCCESS
|
||||
}
|
||||
];
|
||||
|
||||
const store = mockStore({});
|
||||
return store.dispatch(createRepo(URL, slartiFjords)).then(() => {
|
||||
expect(store.getActions()).toEqual(expectedActions);
|
||||
});
|
||||
});
|
||||
|
||||
it("should successfully create repo slarti/fjords and call the callback", () => {
|
||||
fetchMock.postOnce(REPOS_URL, {
|
||||
status: 201,
|
||||
headers: {
|
||||
location: "repositories/slarti/fjords"
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
fetchMock.getOnce(REPOS_URL + "/slarti/fjords", slartiFjords);
|
||||
|
||||
let callMe = "not yet";
|
||||
|
||||
const callback = (r: any) => {
|
||||
expect(r).toEqual(slartiFjords);
|
||||
callMe = "yeah";
|
||||
};
|
||||
|
||||
const store = mockStore({});
|
||||
return store.dispatch(createRepo(URL, slartiFjords, callback)).then(() => {
|
||||
expect(callMe).toBe("yeah");
|
||||
});
|
||||
});
|
||||
|
||||
it("should dispatch failure if server returns status code 500", () => {
|
||||
fetchMock.postOnce(REPOS_URL, {
|
||||
status: 500
|
||||
});
|
||||
|
||||
const store = mockStore({});
|
||||
return store.dispatch(createRepo(URL, slartiFjords)).then(() => {
|
||||
const actions = store.getActions();
|
||||
expect(actions[0].type).toEqual(CREATE_REPO_PENDING);
|
||||
expect(actions[1].type).toEqual(CREATE_REPO_FAILURE);
|
||||
expect(actions[1].payload).toBeDefined();
|
||||
});
|
||||
});
|
||||
|
||||
it("should successfully delete repo slarti/fjords", () => {
|
||||
fetchMock.delete(
|
||||
"http://localhost:8081/api/v2/repositories/slarti/fjords",
|
||||
{
|
||||
status: 204
|
||||
}
|
||||
);
|
||||
|
||||
const expectedActions = [
|
||||
{
|
||||
type: DELETE_REPO_PENDING,
|
||||
payload: slartiFjords,
|
||||
itemId: "slarti/fjords"
|
||||
},
|
||||
{
|
||||
type: DELETE_REPO_SUCCESS,
|
||||
payload: slartiFjords,
|
||||
itemId: "slarti/fjords"
|
||||
}
|
||||
];
|
||||
|
||||
const store = mockStore({});
|
||||
return store.dispatch(deleteRepo(slartiFjords)).then(() => {
|
||||
expect(store.getActions()).toEqual(expectedActions);
|
||||
});
|
||||
});
|
||||
|
||||
it("should successfully delete repo slarti/fjords and call the callback", () => {
|
||||
fetchMock.delete(
|
||||
"http://localhost:8081/api/v2/repositories/slarti/fjords",
|
||||
{
|
||||
status: 204
|
||||
}
|
||||
);
|
||||
|
||||
let callMe = "not yet";
|
||||
|
||||
const callback = () => {
|
||||
callMe = "yeah";
|
||||
};
|
||||
|
||||
const store = mockStore({});
|
||||
return store.dispatch(deleteRepo(slartiFjords, callback)).then(() => {
|
||||
expect(callMe).toBe("yeah");
|
||||
});
|
||||
});
|
||||
|
||||
it("should disapatch failure on delete, if server returns status code 500", () => {
|
||||
fetchMock.delete(
|
||||
"http://localhost:8081/api/v2/repositories/slarti/fjords",
|
||||
{
|
||||
status: 500
|
||||
}
|
||||
);
|
||||
|
||||
const store = mockStore({});
|
||||
return store.dispatch(deleteRepo(slartiFjords)).then(() => {
|
||||
const actions = store.getActions();
|
||||
expect(actions[0].type).toEqual(DELETE_REPO_PENDING);
|
||||
expect(actions[1].type).toEqual(DELETE_REPO_FAILURE);
|
||||
expect(actions[1].payload.repository).toBe(slartiFjords);
|
||||
expect(actions[1].payload.error).toBeDefined();
|
||||
});
|
||||
});
|
||||
|
||||
it("should successfully modify slarti/fjords repo", () => {
|
||||
fetchMock.putOnce(slartiFjords._links.update.href, {
|
||||
status: 204
|
||||
});
|
||||
fetchMock.getOnce(
|
||||
"http://localhost:8081/api/v2/repositories/slarti/fjords",
|
||||
{
|
||||
status: 500
|
||||
}
|
||||
);
|
||||
|
||||
let editedFjords = { ...slartiFjords };
|
||||
editedFjords.description = "coast of africa";
|
||||
|
||||
const store = mockStore({});
|
||||
|
||||
return store.dispatch(modifyRepo(editedFjords)).then(() => {
|
||||
const actions = store.getActions();
|
||||
expect(actions[0].type).toEqual(MODIFY_REPO_PENDING);
|
||||
expect(actions[1].type).toEqual(MODIFY_REPO_SUCCESS);
|
||||
expect(actions[2].type).toEqual(FETCH_REPO_PENDING);
|
||||
});
|
||||
});
|
||||
|
||||
it("should successfully modify slarti/fjords repo and call the callback", () => {
|
||||
fetchMock.putOnce(slartiFjords._links.update.href, {
|
||||
status: 204
|
||||
});
|
||||
fetchMock.getOnce(
|
||||
"http://localhost:8081/api/v2/repositories/slarti/fjords",
|
||||
{
|
||||
status: 500
|
||||
}
|
||||
);
|
||||
|
||||
let editedFjords = { ...slartiFjords };
|
||||
editedFjords.description = "coast of africa";
|
||||
|
||||
const store = mockStore({});
|
||||
|
||||
let called = false;
|
||||
const callback = () => {
|
||||
called = true;
|
||||
};
|
||||
|
||||
return store.dispatch(modifyRepo(editedFjords, callback)).then(() => {
|
||||
const actions = store.getActions();
|
||||
expect(actions[0].type).toEqual(MODIFY_REPO_PENDING);
|
||||
expect(actions[1].type).toEqual(MODIFY_REPO_SUCCESS);
|
||||
expect(actions[2].type).toEqual(FETCH_REPO_PENDING);
|
||||
expect(called).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
it("should fail modifying on HTTP 500", () => {
|
||||
fetchMock.putOnce(slartiFjords._links.update.href, {
|
||||
status: 500
|
||||
});
|
||||
|
||||
let editedFjords = { ...slartiFjords };
|
||||
editedFjords.description = "coast of africa";
|
||||
|
||||
const store = mockStore({});
|
||||
|
||||
return store.dispatch(modifyRepo(editedFjords)).then(() => {
|
||||
const actions = store.getActions();
|
||||
expect(actions[0].type).toEqual(MODIFY_REPO_PENDING);
|
||||
expect(actions[1].type).toEqual(MODIFY_REPO_FAILURE);
|
||||
expect(actions[1].payload).toBeDefined();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("repos reducer", () => {
|
||||
it("should return empty object, if state and action is undefined", () => {
|
||||
expect(reducer()).toEqual({});
|
||||
});
|
||||
|
||||
it("should return the same state, if the action is undefined", () => {
|
||||
const state = { x: true };
|
||||
expect(reducer(state)).toBe(state);
|
||||
});
|
||||
|
||||
it("should return the same state, if the action is unknown to the reducer", () => {
|
||||
const state = { x: true };
|
||||
expect(reducer(state, { type: "EL_SPECIALE" })).toBe(state);
|
||||
});
|
||||
|
||||
it("should store the repositories by it's namespace and name on FETCH_REPOS_SUCCESS", () => {
|
||||
const newState = reducer({}, fetchReposSuccess(repositoryCollection));
|
||||
expect(newState.list.page).toBe(0);
|
||||
expect(newState.list.pageTotal).toBe(1);
|
||||
expect(newState.list._embedded.repositories).toEqual([
|
||||
"hitchhiker/puzzle42",
|
||||
"hitchhiker/restatend",
|
||||
"slarti/fjords"
|
||||
]);
|
||||
|
||||
expect(newState.byNames["hitchhiker/puzzle42"]).toBe(hitchhikerPuzzle42);
|
||||
expect(newState.byNames["hitchhiker/restatend"]).toBe(hitchhikerRestatend);
|
||||
expect(newState.byNames["slarti/fjords"]).toBe(slartiFjords);
|
||||
});
|
||||
|
||||
it("should store the repo at byNames", () => {
|
||||
const newState = reducer({}, fetchRepoSuccess(slartiFjords));
|
||||
expect(newState.byNames["slarti/fjords"]).toBe(slartiFjords);
|
||||
});
|
||||
});
|
||||
|
||||
describe("repos selectors", () => {
|
||||
const error = new Error("something goes wrong");
|
||||
|
||||
it("should return the repositories collection", () => {
|
||||
const state = {
|
||||
repos: {
|
||||
list: repositoryCollectionWithNames,
|
||||
byNames: {
|
||||
"hitchhiker/puzzle42": hitchhikerPuzzle42,
|
||||
"hitchhiker/restatend": hitchhikerRestatend,
|
||||
"slarti/fjords": slartiFjords
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const collection = getRepositoryCollection(state);
|
||||
expect(collection).toEqual(repositoryCollection);
|
||||
});
|
||||
|
||||
it("should return true, when fetch repos is pending", () => {
|
||||
const state = {
|
||||
pending: {
|
||||
[FETCH_REPOS]: true
|
||||
}
|
||||
};
|
||||
expect(isFetchReposPending(state)).toEqual(true);
|
||||
});
|
||||
|
||||
it("should return false, when fetch repos is not pending", () => {
|
||||
expect(isFetchReposPending({})).toEqual(false);
|
||||
});
|
||||
|
||||
it("should return error when fetch repos did fail", () => {
|
||||
const state = {
|
||||
failure: {
|
||||
[FETCH_REPOS]: error
|
||||
}
|
||||
};
|
||||
expect(getFetchReposFailure(state)).toEqual(error);
|
||||
});
|
||||
|
||||
it("should return undefined when fetch repos did not fail", () => {
|
||||
expect(getFetchReposFailure({})).toBe(undefined);
|
||||
});
|
||||
|
||||
it("should return the repository collection", () => {
|
||||
const state = {
|
||||
repos: {
|
||||
byNames: {
|
||||
"slarti/fjords": slartiFjords
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const repository = getRepository(state, "slarti", "fjords");
|
||||
expect(repository).toEqual(slartiFjords);
|
||||
});
|
||||
|
||||
it("should return permissions link", () => {
|
||||
const state = {
|
||||
repos: {
|
||||
byNames: {
|
||||
"slarti/fjords": slartiFjords
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const link = getPermissionsLink(state, "slarti", "fjords");
|
||||
expect(link).toEqual(
|
||||
"http://localhost:8081/api/v2/repositories/slarti/fjords/permissions/"
|
||||
);
|
||||
});
|
||||
|
||||
it("should return true, when fetch repo is pending", () => {
|
||||
const state = {
|
||||
pending: {
|
||||
[FETCH_REPO + "/slarti/fjords"]: true
|
||||
}
|
||||
};
|
||||
expect(isFetchRepoPending(state, "slarti", "fjords")).toEqual(true);
|
||||
});
|
||||
|
||||
it("should return false, when fetch repo is not pending", () => {
|
||||
expect(isFetchRepoPending({}, "slarti", "fjords")).toEqual(false);
|
||||
});
|
||||
|
||||
it("should return error when fetch repo did fail", () => {
|
||||
const state = {
|
||||
failure: {
|
||||
[FETCH_REPO + "/slarti/fjords"]: error
|
||||
}
|
||||
};
|
||||
expect(getFetchRepoFailure(state, "slarti", "fjords")).toEqual(error);
|
||||
});
|
||||
|
||||
it("should return undefined when fetch repo did not fail", () => {
|
||||
expect(getFetchRepoFailure({}, "slarti", "fjords")).toBe(undefined);
|
||||
});
|
||||
|
||||
// create
|
||||
|
||||
it("should return true, when create repo is pending", () => {
|
||||
const state = {
|
||||
pending: {
|
||||
[CREATE_REPO]: true
|
||||
}
|
||||
};
|
||||
expect(isCreateRepoPending(state)).toEqual(true);
|
||||
});
|
||||
|
||||
it("should return false, when create repo is not pending", () => {
|
||||
expect(isCreateRepoPending({})).toEqual(false);
|
||||
});
|
||||
|
||||
it("should return error when create repo did fail", () => {
|
||||
const state = {
|
||||
failure: {
|
||||
[CREATE_REPO]: error
|
||||
}
|
||||
};
|
||||
expect(getCreateRepoFailure(state)).toEqual(error);
|
||||
});
|
||||
|
||||
it("should return undefined when create repo did not fail", () => {
|
||||
expect(getCreateRepoFailure({})).toBe(undefined);
|
||||
});
|
||||
|
||||
// modify
|
||||
|
||||
it("should return true, when modify repo is pending", () => {
|
||||
const state = {
|
||||
pending: {
|
||||
[MODIFY_REPO + "/slarti/fjords"]: true
|
||||
}
|
||||
};
|
||||
|
||||
expect(isModifyRepoPending(state, "slarti", "fjords")).toEqual(true);
|
||||
});
|
||||
|
||||
it("should return false, when modify repo is not pending", () => {
|
||||
expect(isModifyRepoPending({}, "slarti", "fjords")).toEqual(false);
|
||||
});
|
||||
|
||||
it("should return error, when modify repo failed", () => {
|
||||
const state = {
|
||||
failure: {
|
||||
[MODIFY_REPO + "/slarti/fjords"]: error
|
||||
}
|
||||
};
|
||||
|
||||
expect(getModifyRepoFailure(state, "slarti", "fjords")).toEqual(error);
|
||||
});
|
||||
|
||||
it("should return undefined, when modify did not fail", () => {
|
||||
expect(getModifyRepoFailure({}, "slarti", "fjords")).toBeUndefined();
|
||||
});
|
||||
|
||||
// delete
|
||||
|
||||
it("should return true, when delete repo is pending", () => {
|
||||
const state = {
|
||||
pending: {
|
||||
[DELETE_REPO + "/slarti/fjords"]: true
|
||||
}
|
||||
};
|
||||
expect(isDeleteRepoPending(state, "slarti", "fjords")).toEqual(true);
|
||||
});
|
||||
|
||||
it("should return false, when delete repo is not pending", () => {
|
||||
expect(isDeleteRepoPending({}, "slarti", "fjords")).toEqual(false);
|
||||
});
|
||||
|
||||
it("should return error when delete repo did fail", () => {
|
||||
const state = {
|
||||
failure: {
|
||||
[DELETE_REPO + "/slarti/fjords"]: error
|
||||
}
|
||||
};
|
||||
expect(getDeleteRepoFailure(state, "slarti", "fjords")).toEqual(error);
|
||||
});
|
||||
|
||||
it("should return undefined when delete repo did not fail", () => {
|
||||
expect(getDeleteRepoFailure({}, "slarti", "fjords")).toBe(undefined);
|
||||
});
|
||||
|
||||
it("should return true if the list contains the create link", () => {
|
||||
const state = {
|
||||
repos: {
|
||||
list: repositoryCollection
|
||||
}
|
||||
};
|
||||
|
||||
expect(isAbleToCreateRepos(state)).toBe(true);
|
||||
});
|
||||
|
||||
it("should return false, if create link is unavailable", () => {
|
||||
const state = {
|
||||
repos: {
|
||||
list: {
|
||||
_links: {}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
expect(isAbleToCreateRepos(state)).toBe(false);
|
||||
});
|
||||
});
|
||||
878
scm-ui/ui-webapp/src/repos/modules/repos.test.ts
Normal file
878
scm-ui/ui-webapp/src/repos/modules/repos.test.ts
Normal file
@@ -0,0 +1,878 @@
|
||||
import configureMockStore from 'redux-mock-store';
|
||||
import thunk from 'redux-thunk';
|
||||
import fetchMock from 'fetch-mock';
|
||||
import reducer, {
|
||||
FETCH_REPOS_PENDING,
|
||||
FETCH_REPOS_SUCCESS,
|
||||
fetchRepos,
|
||||
FETCH_REPOS_FAILURE,
|
||||
fetchReposSuccess,
|
||||
getRepositoryCollection,
|
||||
FETCH_REPOS,
|
||||
isFetchReposPending,
|
||||
getFetchReposFailure,
|
||||
fetchReposByLink,
|
||||
fetchReposByPage,
|
||||
FETCH_REPO,
|
||||
fetchRepoByLink,
|
||||
fetchRepoByName,
|
||||
FETCH_REPO_PENDING,
|
||||
FETCH_REPO_SUCCESS,
|
||||
FETCH_REPO_FAILURE,
|
||||
fetchRepoSuccess,
|
||||
getRepository,
|
||||
isFetchRepoPending,
|
||||
getFetchRepoFailure,
|
||||
CREATE_REPO_PENDING,
|
||||
CREATE_REPO_SUCCESS,
|
||||
createRepo,
|
||||
CREATE_REPO_FAILURE,
|
||||
isCreateRepoPending,
|
||||
CREATE_REPO,
|
||||
getCreateRepoFailure,
|
||||
isAbleToCreateRepos,
|
||||
DELETE_REPO,
|
||||
DELETE_REPO_SUCCESS,
|
||||
deleteRepo,
|
||||
DELETE_REPO_PENDING,
|
||||
DELETE_REPO_FAILURE,
|
||||
isDeleteRepoPending,
|
||||
getDeleteRepoFailure,
|
||||
modifyRepo,
|
||||
MODIFY_REPO_PENDING,
|
||||
MODIFY_REPO_SUCCESS,
|
||||
MODIFY_REPO_FAILURE,
|
||||
MODIFY_REPO,
|
||||
isModifyRepoPending,
|
||||
getModifyRepoFailure,
|
||||
getPermissionsLink,
|
||||
} from './repos';
|
||||
import { Repository, RepositoryCollection } from '@scm-manager/ui-types';
|
||||
|
||||
const hitchhikerPuzzle42: Repository = {
|
||||
contact: 'fourtytwo@hitchhiker.com',
|
||||
creationDate: '2018-07-31T08:58:45.961Z',
|
||||
description: 'the answer to life the universe and everything',
|
||||
namespace: 'hitchhiker',
|
||||
name: 'puzzle42',
|
||||
type: 'svn',
|
||||
_links: {
|
||||
self: {
|
||||
href: 'http://localhost:8081/api/v2/repositories/hitchhiker/puzzle42',
|
||||
},
|
||||
delete: {
|
||||
href: 'http://localhost:8081/api/v2/repositories/hitchhiker/puzzle42',
|
||||
},
|
||||
update: {
|
||||
href: 'http://localhost:8081/api/v2/repositories/hitchhiker/puzzle42',
|
||||
},
|
||||
permissions: {
|
||||
href:
|
||||
'http://localhost:8081/api/v2/repositories/hitchhiker/puzzle42/permissions/',
|
||||
},
|
||||
tags: {
|
||||
href:
|
||||
'http://localhost:8081/api/v2/repositories/hitchhiker/puzzle42/tags/',
|
||||
},
|
||||
branches: {
|
||||
href:
|
||||
'http://localhost:8081/api/v2/repositories/hitchhiker/puzzle42/branches/',
|
||||
},
|
||||
changesets: {
|
||||
href:
|
||||
'http://localhost:8081/api/v2/repositories/hitchhiker/puzzle42/changesets/',
|
||||
},
|
||||
sources: {
|
||||
href:
|
||||
'http://localhost:8081/api/v2/repositories/hitchhiker/puzzle42/sources/',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const hitchhikerRestatend: Repository = {
|
||||
contact: 'restatend@hitchhiker.com',
|
||||
creationDate: '2018-07-31T08:58:32.803Z',
|
||||
description: 'restaurant at the end of the universe',
|
||||
namespace: 'hitchhiker',
|
||||
name: 'restatend',
|
||||
type: 'git',
|
||||
_links: {
|
||||
self: {
|
||||
href: 'http://localhost:8081/api/v2/repositories/hitchhiker/restatend',
|
||||
},
|
||||
delete: {
|
||||
href: 'http://localhost:8081/api/v2/repositories/hitchhiker/restatend',
|
||||
},
|
||||
update: {
|
||||
href: 'http://localhost:8081/api/v2/repositories/hitchhiker/restatend',
|
||||
},
|
||||
permissions: {
|
||||
href:
|
||||
'http://localhost:8081/api/v2/repositories/hitchhiker/restatend/permissions/',
|
||||
},
|
||||
tags: {
|
||||
href:
|
||||
'http://localhost:8081/api/v2/repositories/hitchhiker/restatend/tags/',
|
||||
},
|
||||
branches: {
|
||||
href:
|
||||
'http://localhost:8081/api/v2/repositories/hitchhiker/restatend/branches/',
|
||||
},
|
||||
changesets: {
|
||||
href:
|
||||
'http://localhost:8081/api/v2/repositories/hitchhiker/restatend/changesets/',
|
||||
},
|
||||
sources: {
|
||||
href:
|
||||
'http://localhost:8081/api/v2/repositories/hitchhiker/restatend/sources/',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const slartiFjords: Repository = {
|
||||
contact: 'slartibartfast@hitchhiker.com',
|
||||
description: 'My award-winning fjords from the Norwegian coast',
|
||||
namespace: 'slarti',
|
||||
name: 'fjords',
|
||||
type: 'hg',
|
||||
creationDate: '2018-07-31T08:59:05.653Z',
|
||||
_links: {
|
||||
self: {
|
||||
href: 'http://localhost:8081/api/v2/repositories/slarti/fjords',
|
||||
},
|
||||
delete: {
|
||||
href: 'http://localhost:8081/api/v2/repositories/slarti/fjords',
|
||||
},
|
||||
update: {
|
||||
href: 'http://localhost:8081/api/v2/repositories/slarti/fjords',
|
||||
},
|
||||
permissions: {
|
||||
href:
|
||||
'http://localhost:8081/api/v2/repositories/slarti/fjords/permissions/',
|
||||
},
|
||||
tags: {
|
||||
href: 'http://localhost:8081/api/v2/repositories/slarti/fjords/tags/',
|
||||
},
|
||||
branches: {
|
||||
href: 'http://localhost:8081/api/v2/repositories/slarti/fjords/branches/',
|
||||
},
|
||||
changesets: {
|
||||
href:
|
||||
'http://localhost:8081/api/v2/repositories/slarti/fjords/changesets/',
|
||||
},
|
||||
sources: {
|
||||
href: 'http://localhost:8081/api/v2/repositories/slarti/fjords/sources/',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const repositoryCollection: RepositoryCollection = {
|
||||
page: 0,
|
||||
pageTotal: 1,
|
||||
_links: {
|
||||
self: {
|
||||
href: 'http://localhost:8081/api/v2/repositories/?page=0&pageSize=10',
|
||||
},
|
||||
first: {
|
||||
href: 'http://localhost:8081/api/v2/repositories/?page=0&pageSize=10',
|
||||
},
|
||||
last: {
|
||||
href: 'http://localhost:8081/api/v2/repositories/?page=0&pageSize=10',
|
||||
},
|
||||
create: {
|
||||
href: 'http://localhost:8081/api/v2/repositories/',
|
||||
},
|
||||
},
|
||||
_embedded: {
|
||||
repositories: [hitchhikerPuzzle42, hitchhikerRestatend, slartiFjords],
|
||||
},
|
||||
};
|
||||
|
||||
const repositoryCollectionWithNames: RepositoryCollection = {
|
||||
page: 0,
|
||||
pageTotal: 1,
|
||||
_links: {
|
||||
self: {
|
||||
href: 'http://localhost:8081/api/v2/repositories/?page=0&pageSize=10',
|
||||
},
|
||||
first: {
|
||||
href: 'http://localhost:8081/api/v2/repositories/?page=0&pageSize=10',
|
||||
},
|
||||
last: {
|
||||
href: 'http://localhost:8081/api/v2/repositories/?page=0&pageSize=10',
|
||||
},
|
||||
create: {
|
||||
href: 'http://localhost:8081/api/v2/repositories/',
|
||||
},
|
||||
},
|
||||
_embedded: {
|
||||
repositories: [
|
||||
'hitchhiker/puzzle42',
|
||||
'hitchhiker/restatend',
|
||||
'slarti/fjords',
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
describe('repos fetch', () => {
|
||||
const URL = 'repositories';
|
||||
const REPOS_URL = '/api/v2/repositories';
|
||||
const SORT = 'sortBy=namespaceAndName';
|
||||
const REPOS_URL_WITH_SORT = REPOS_URL + '?' + SORT;
|
||||
const mockStore = configureMockStore([thunk]);
|
||||
|
||||
afterEach(() => {
|
||||
fetchMock.reset();
|
||||
fetchMock.restore();
|
||||
});
|
||||
|
||||
it('should successfully fetch repos', () => {
|
||||
fetchMock.getOnce(REPOS_URL_WITH_SORT, repositoryCollection);
|
||||
|
||||
const expectedActions = [
|
||||
{
|
||||
type: FETCH_REPOS_PENDING,
|
||||
},
|
||||
{
|
||||
type: FETCH_REPOS_SUCCESS,
|
||||
payload: repositoryCollection,
|
||||
},
|
||||
];
|
||||
|
||||
const store = mockStore({});
|
||||
return store.dispatch(fetchRepos(URL)).then(() => {
|
||||
expect(store.getActions()).toEqual(expectedActions);
|
||||
});
|
||||
});
|
||||
|
||||
it('should successfully fetch page 42', () => {
|
||||
const url = REPOS_URL + '?page=42&' + SORT;
|
||||
fetchMock.getOnce(url, repositoryCollection);
|
||||
|
||||
const expectedActions = [
|
||||
{
|
||||
type: FETCH_REPOS_PENDING,
|
||||
},
|
||||
{
|
||||
type: FETCH_REPOS_SUCCESS,
|
||||
payload: repositoryCollection,
|
||||
},
|
||||
];
|
||||
|
||||
const store = mockStore({});
|
||||
|
||||
return store.dispatch(fetchReposByPage(URL, 43)).then(() => {
|
||||
expect(store.getActions()).toEqual(expectedActions);
|
||||
});
|
||||
});
|
||||
|
||||
it('should successfully fetch repos from link', () => {
|
||||
fetchMock.getOnce(
|
||||
REPOS_URL + '?' + SORT + '&page=42',
|
||||
repositoryCollection,
|
||||
);
|
||||
|
||||
const expectedActions = [
|
||||
{
|
||||
type: FETCH_REPOS_PENDING,
|
||||
},
|
||||
{
|
||||
type: FETCH_REPOS_SUCCESS,
|
||||
payload: repositoryCollection,
|
||||
},
|
||||
];
|
||||
|
||||
const store = mockStore({});
|
||||
return store
|
||||
.dispatch(
|
||||
fetchReposByLink('/repositories?sortBy=namespaceAndName&page=42'),
|
||||
)
|
||||
.then(() => {
|
||||
expect(store.getActions()).toEqual(expectedActions);
|
||||
});
|
||||
});
|
||||
|
||||
it('should append sortby parameter and successfully fetch repos from link', () => {
|
||||
fetchMock.getOnce(
|
||||
'/api/v2/repositories?one=1&sortBy=namespaceAndName',
|
||||
repositoryCollection,
|
||||
);
|
||||
|
||||
const expectedActions = [
|
||||
{
|
||||
type: FETCH_REPOS_PENDING,
|
||||
},
|
||||
{
|
||||
type: FETCH_REPOS_SUCCESS,
|
||||
payload: repositoryCollection,
|
||||
},
|
||||
];
|
||||
|
||||
const store = mockStore({});
|
||||
|
||||
return store.dispatch(fetchReposByLink('/repositories?one=1')).then(() => {
|
||||
expect(store.getActions()).toEqual(expectedActions);
|
||||
});
|
||||
});
|
||||
|
||||
it('should dispatch FETCH_REPOS_FAILURE, it the request fails', () => {
|
||||
fetchMock.getOnce(REPOS_URL_WITH_SORT, {
|
||||
status: 500,
|
||||
});
|
||||
|
||||
const store = mockStore({});
|
||||
return store.dispatch(fetchRepos(URL)).then(() => {
|
||||
const actions = store.getActions();
|
||||
expect(actions[0].type).toEqual(FETCH_REPOS_PENDING);
|
||||
expect(actions[1].type).toEqual(FETCH_REPOS_FAILURE);
|
||||
expect(actions[1].payload).toBeDefined();
|
||||
});
|
||||
});
|
||||
|
||||
it('should successfully fetch repo slarti/fjords by name', () => {
|
||||
fetchMock.getOnce(REPOS_URL + '/slarti/fjords', slartiFjords);
|
||||
|
||||
const expectedActions = [
|
||||
{
|
||||
type: FETCH_REPO_PENDING,
|
||||
payload: {
|
||||
namespace: 'slarti',
|
||||
name: 'fjords',
|
||||
},
|
||||
itemId: 'slarti/fjords',
|
||||
},
|
||||
{
|
||||
type: FETCH_REPO_SUCCESS,
|
||||
payload: slartiFjords,
|
||||
itemId: 'slarti/fjords',
|
||||
},
|
||||
];
|
||||
|
||||
const store = mockStore({});
|
||||
return store.dispatch(fetchRepoByName(URL, 'slarti', 'fjords')).then(() => {
|
||||
expect(store.getActions()).toEqual(expectedActions);
|
||||
});
|
||||
});
|
||||
|
||||
it('should dispatch FETCH_REPO_FAILURE, if the request for slarti/fjords by name fails', () => {
|
||||
fetchMock.getOnce(REPOS_URL + '/slarti/fjords', {
|
||||
status: 500,
|
||||
});
|
||||
|
||||
const store = mockStore({});
|
||||
return store.dispatch(fetchRepoByName(URL, 'slarti', 'fjords')).then(() => {
|
||||
const actions = store.getActions();
|
||||
expect(actions[0].type).toEqual(FETCH_REPO_PENDING);
|
||||
expect(actions[1].type).toEqual(FETCH_REPO_FAILURE);
|
||||
expect(actions[1].payload.namespace).toBe('slarti');
|
||||
expect(actions[1].payload.name).toBe('fjords');
|
||||
expect(actions[1].payload.error).toBeDefined();
|
||||
expect(actions[1].itemId).toBe('slarti/fjords');
|
||||
});
|
||||
});
|
||||
|
||||
it('should successfully fetch repo slarti/fjords', () => {
|
||||
fetchMock.getOnce(
|
||||
'http://localhost:8081/api/v2/repositories/slarti/fjords',
|
||||
slartiFjords,
|
||||
);
|
||||
|
||||
const expectedActions = [
|
||||
{
|
||||
type: FETCH_REPO_PENDING,
|
||||
payload: {
|
||||
namespace: 'slarti',
|
||||
name: 'fjords',
|
||||
},
|
||||
itemId: 'slarti/fjords',
|
||||
},
|
||||
{
|
||||
type: FETCH_REPO_SUCCESS,
|
||||
payload: slartiFjords,
|
||||
itemId: 'slarti/fjords',
|
||||
},
|
||||
];
|
||||
|
||||
const store = mockStore({});
|
||||
return store.dispatch(fetchRepoByLink(slartiFjords)).then(() => {
|
||||
expect(store.getActions()).toEqual(expectedActions);
|
||||
});
|
||||
});
|
||||
|
||||
it('should dispatch FETCH_REPO_FAILURE, it the request for slarti/fjords fails', () => {
|
||||
fetchMock.getOnce(
|
||||
'http://localhost:8081/api/v2/repositories/slarti/fjords',
|
||||
{
|
||||
status: 500,
|
||||
},
|
||||
);
|
||||
|
||||
const store = mockStore({});
|
||||
return store.dispatch(fetchRepoByLink(slartiFjords)).then(() => {
|
||||
const actions = store.getActions();
|
||||
expect(actions[0].type).toEqual(FETCH_REPO_PENDING);
|
||||
expect(actions[1].type).toEqual(FETCH_REPO_FAILURE);
|
||||
expect(actions[1].payload.namespace).toBe('slarti');
|
||||
expect(actions[1].payload.name).toBe('fjords');
|
||||
expect(actions[1].payload.error).toBeDefined();
|
||||
expect(actions[1].itemId).toBe('slarti/fjords');
|
||||
});
|
||||
});
|
||||
|
||||
it('should successfully create repo slarti/fjords', () => {
|
||||
fetchMock.postOnce(REPOS_URL, {
|
||||
status: 201,
|
||||
headers: {
|
||||
location: 'repositories/slarti/fjords',
|
||||
},
|
||||
});
|
||||
|
||||
fetchMock.getOnce(REPOS_URL + '/slarti/fjords', slartiFjords);
|
||||
|
||||
const expectedActions = [
|
||||
{
|
||||
type: CREATE_REPO_PENDING,
|
||||
},
|
||||
{
|
||||
type: CREATE_REPO_SUCCESS,
|
||||
},
|
||||
];
|
||||
|
||||
const store = mockStore({});
|
||||
return store.dispatch(createRepo(URL, slartiFjords)).then(() => {
|
||||
expect(store.getActions()).toEqual(expectedActions);
|
||||
});
|
||||
});
|
||||
|
||||
it('should successfully create repo slarti/fjords and call the callback', () => {
|
||||
fetchMock.postOnce(REPOS_URL, {
|
||||
status: 201,
|
||||
headers: {
|
||||
location: 'repositories/slarti/fjords',
|
||||
},
|
||||
});
|
||||
|
||||
fetchMock.getOnce(REPOS_URL + '/slarti/fjords', slartiFjords);
|
||||
|
||||
let callMe = 'not yet';
|
||||
|
||||
const callback = (r: any) => {
|
||||
expect(r).toEqual(slartiFjords);
|
||||
callMe = 'yeah';
|
||||
};
|
||||
|
||||
const store = mockStore({});
|
||||
return store.dispatch(createRepo(URL, slartiFjords, callback)).then(() => {
|
||||
expect(callMe).toBe('yeah');
|
||||
});
|
||||
});
|
||||
|
||||
it('should dispatch failure if server returns status code 500', () => {
|
||||
fetchMock.postOnce(REPOS_URL, {
|
||||
status: 500,
|
||||
});
|
||||
|
||||
const store = mockStore({});
|
||||
return store.dispatch(createRepo(URL, slartiFjords)).then(() => {
|
||||
const actions = store.getActions();
|
||||
expect(actions[0].type).toEqual(CREATE_REPO_PENDING);
|
||||
expect(actions[1].type).toEqual(CREATE_REPO_FAILURE);
|
||||
expect(actions[1].payload).toBeDefined();
|
||||
});
|
||||
});
|
||||
|
||||
it('should successfully delete repo slarti/fjords', () => {
|
||||
fetchMock.delete(
|
||||
'http://localhost:8081/api/v2/repositories/slarti/fjords',
|
||||
{
|
||||
status: 204,
|
||||
},
|
||||
);
|
||||
|
||||
const expectedActions = [
|
||||
{
|
||||
type: DELETE_REPO_PENDING,
|
||||
payload: slartiFjords,
|
||||
itemId: 'slarti/fjords',
|
||||
},
|
||||
{
|
||||
type: DELETE_REPO_SUCCESS,
|
||||
payload: slartiFjords,
|
||||
itemId: 'slarti/fjords',
|
||||
},
|
||||
];
|
||||
|
||||
const store = mockStore({});
|
||||
return store.dispatch(deleteRepo(slartiFjords)).then(() => {
|
||||
expect(store.getActions()).toEqual(expectedActions);
|
||||
});
|
||||
});
|
||||
|
||||
it('should successfully delete repo slarti/fjords and call the callback', () => {
|
||||
fetchMock.delete(
|
||||
'http://localhost:8081/api/v2/repositories/slarti/fjords',
|
||||
{
|
||||
status: 204,
|
||||
},
|
||||
);
|
||||
|
||||
let callMe = 'not yet';
|
||||
|
||||
const callback = () => {
|
||||
callMe = 'yeah';
|
||||
};
|
||||
|
||||
const store = mockStore({});
|
||||
return store.dispatch(deleteRepo(slartiFjords, callback)).then(() => {
|
||||
expect(callMe).toBe('yeah');
|
||||
});
|
||||
});
|
||||
|
||||
it('should disapatch failure on delete, if server returns status code 500', () => {
|
||||
fetchMock.delete(
|
||||
'http://localhost:8081/api/v2/repositories/slarti/fjords',
|
||||
{
|
||||
status: 500,
|
||||
},
|
||||
);
|
||||
|
||||
const store = mockStore({});
|
||||
return store.dispatch(deleteRepo(slartiFjords)).then(() => {
|
||||
const actions = store.getActions();
|
||||
expect(actions[0].type).toEqual(DELETE_REPO_PENDING);
|
||||
expect(actions[1].type).toEqual(DELETE_REPO_FAILURE);
|
||||
expect(actions[1].payload.repository).toBe(slartiFjords);
|
||||
expect(actions[1].payload.error).toBeDefined();
|
||||
});
|
||||
});
|
||||
|
||||
it('should successfully modify slarti/fjords repo', () => {
|
||||
fetchMock.putOnce(slartiFjords._links.update.href, {
|
||||
status: 204,
|
||||
});
|
||||
fetchMock.getOnce(
|
||||
'http://localhost:8081/api/v2/repositories/slarti/fjords',
|
||||
{
|
||||
status: 500,
|
||||
},
|
||||
);
|
||||
|
||||
let editedFjords = {
|
||||
...slartiFjords,
|
||||
};
|
||||
editedFjords.description = 'coast of africa';
|
||||
|
||||
const store = mockStore({});
|
||||
|
||||
return store.dispatch(modifyRepo(editedFjords)).then(() => {
|
||||
const actions = store.getActions();
|
||||
expect(actions[0].type).toEqual(MODIFY_REPO_PENDING);
|
||||
expect(actions[1].type).toEqual(MODIFY_REPO_SUCCESS);
|
||||
expect(actions[2].type).toEqual(FETCH_REPO_PENDING);
|
||||
});
|
||||
});
|
||||
|
||||
it('should successfully modify slarti/fjords repo and call the callback', () => {
|
||||
fetchMock.putOnce(slartiFjords._links.update.href, {
|
||||
status: 204,
|
||||
});
|
||||
fetchMock.getOnce(
|
||||
'http://localhost:8081/api/v2/repositories/slarti/fjords',
|
||||
{
|
||||
status: 500,
|
||||
},
|
||||
);
|
||||
|
||||
let editedFjords = {
|
||||
...slartiFjords,
|
||||
};
|
||||
editedFjords.description = 'coast of africa';
|
||||
|
||||
const store = mockStore({});
|
||||
|
||||
let called = false;
|
||||
const callback = () => {
|
||||
called = true;
|
||||
};
|
||||
|
||||
return store.dispatch(modifyRepo(editedFjords, callback)).then(() => {
|
||||
const actions = store.getActions();
|
||||
expect(actions[0].type).toEqual(MODIFY_REPO_PENDING);
|
||||
expect(actions[1].type).toEqual(MODIFY_REPO_SUCCESS);
|
||||
expect(actions[2].type).toEqual(FETCH_REPO_PENDING);
|
||||
expect(called).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
it('should fail modifying on HTTP 500', () => {
|
||||
fetchMock.putOnce(slartiFjords._links.update.href, {
|
||||
status: 500,
|
||||
});
|
||||
|
||||
let editedFjords = {
|
||||
...slartiFjords,
|
||||
};
|
||||
editedFjords.description = 'coast of africa';
|
||||
|
||||
const store = mockStore({});
|
||||
|
||||
return store.dispatch(modifyRepo(editedFjords)).then(() => {
|
||||
const actions = store.getActions();
|
||||
expect(actions[0].type).toEqual(MODIFY_REPO_PENDING);
|
||||
expect(actions[1].type).toEqual(MODIFY_REPO_FAILURE);
|
||||
expect(actions[1].payload).toBeDefined();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('repos reducer', () => {
|
||||
it('should return empty object, if state and action is undefined', () => {
|
||||
expect(reducer()).toEqual({});
|
||||
});
|
||||
|
||||
it('should return the same state, if the action is undefined', () => {
|
||||
const state = {
|
||||
x: true,
|
||||
};
|
||||
expect(reducer(state)).toBe(state);
|
||||
});
|
||||
|
||||
it('should return the same state, if the action is unknown to the reducer', () => {
|
||||
const state = {
|
||||
x: true,
|
||||
};
|
||||
expect(
|
||||
reducer(state, {
|
||||
type: 'EL_SPECIALE',
|
||||
}),
|
||||
).toBe(state);
|
||||
});
|
||||
|
||||
it("should store the repositories by it's namespace and name on FETCH_REPOS_SUCCESS", () => {
|
||||
const newState = reducer({}, fetchReposSuccess(repositoryCollection));
|
||||
expect(newState.list.page).toBe(0);
|
||||
expect(newState.list.pageTotal).toBe(1);
|
||||
expect(newState.list._embedded.repositories).toEqual([
|
||||
'hitchhiker/puzzle42',
|
||||
'hitchhiker/restatend',
|
||||
'slarti/fjords',
|
||||
]);
|
||||
|
||||
expect(newState.byNames['hitchhiker/puzzle42']).toBe(hitchhikerPuzzle42);
|
||||
expect(newState.byNames['hitchhiker/restatend']).toBe(hitchhikerRestatend);
|
||||
expect(newState.byNames['slarti/fjords']).toBe(slartiFjords);
|
||||
});
|
||||
|
||||
it('should store the repo at byNames', () => {
|
||||
const newState = reducer({}, fetchRepoSuccess(slartiFjords));
|
||||
expect(newState.byNames['slarti/fjords']).toBe(slartiFjords);
|
||||
});
|
||||
});
|
||||
|
||||
describe('repos selectors', () => {
|
||||
const error = new Error('something goes wrong');
|
||||
|
||||
it('should return the repositories collection', () => {
|
||||
const state = {
|
||||
repos: {
|
||||
list: repositoryCollectionWithNames,
|
||||
byNames: {
|
||||
'hitchhiker/puzzle42': hitchhikerPuzzle42,
|
||||
'hitchhiker/restatend': hitchhikerRestatend,
|
||||
'slarti/fjords': slartiFjords,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const collection = getRepositoryCollection(state);
|
||||
expect(collection).toEqual(repositoryCollection);
|
||||
});
|
||||
|
||||
it('should return true, when fetch repos is pending', () => {
|
||||
const state = {
|
||||
pending: {
|
||||
[FETCH_REPOS]: true,
|
||||
},
|
||||
};
|
||||
expect(isFetchReposPending(state)).toEqual(true);
|
||||
});
|
||||
|
||||
it('should return false, when fetch repos is not pending', () => {
|
||||
expect(isFetchReposPending({})).toEqual(false);
|
||||
});
|
||||
|
||||
it('should return error when fetch repos did fail', () => {
|
||||
const state = {
|
||||
failure: {
|
||||
[FETCH_REPOS]: error,
|
||||
},
|
||||
};
|
||||
expect(getFetchReposFailure(state)).toEqual(error);
|
||||
});
|
||||
|
||||
it('should return undefined when fetch repos did not fail', () => {
|
||||
expect(getFetchReposFailure({})).toBe(undefined);
|
||||
});
|
||||
|
||||
it('should return the repository collection', () => {
|
||||
const state = {
|
||||
repos: {
|
||||
byNames: {
|
||||
'slarti/fjords': slartiFjords,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const repository = getRepository(state, 'slarti', 'fjords');
|
||||
expect(repository).toEqual(slartiFjords);
|
||||
});
|
||||
|
||||
it('should return permissions link', () => {
|
||||
const state = {
|
||||
repos: {
|
||||
byNames: {
|
||||
'slarti/fjords': slartiFjords,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const link = getPermissionsLink(state, 'slarti', 'fjords');
|
||||
expect(link).toEqual(
|
||||
'http://localhost:8081/api/v2/repositories/slarti/fjords/permissions/',
|
||||
);
|
||||
});
|
||||
|
||||
it('should return true, when fetch repo is pending', () => {
|
||||
const state = {
|
||||
pending: {
|
||||
[FETCH_REPO + '/slarti/fjords']: true,
|
||||
},
|
||||
};
|
||||
expect(isFetchRepoPending(state, 'slarti', 'fjords')).toEqual(true);
|
||||
});
|
||||
|
||||
it('should return false, when fetch repo is not pending', () => {
|
||||
expect(isFetchRepoPending({}, 'slarti', 'fjords')).toEqual(false);
|
||||
});
|
||||
|
||||
it('should return error when fetch repo did fail', () => {
|
||||
const state = {
|
||||
failure: {
|
||||
[FETCH_REPO + '/slarti/fjords']: error,
|
||||
},
|
||||
};
|
||||
expect(getFetchRepoFailure(state, 'slarti', 'fjords')).toEqual(error);
|
||||
});
|
||||
|
||||
it('should return undefined when fetch repo did not fail', () => {
|
||||
expect(getFetchRepoFailure({}, 'slarti', 'fjords')).toBe(undefined);
|
||||
});
|
||||
|
||||
// create
|
||||
|
||||
it('should return true, when create repo is pending', () => {
|
||||
const state = {
|
||||
pending: {
|
||||
[CREATE_REPO]: true,
|
||||
},
|
||||
};
|
||||
expect(isCreateRepoPending(state)).toEqual(true);
|
||||
});
|
||||
|
||||
it('should return false, when create repo is not pending', () => {
|
||||
expect(isCreateRepoPending({})).toEqual(false);
|
||||
});
|
||||
|
||||
it('should return error when create repo did fail', () => {
|
||||
const state = {
|
||||
failure: {
|
||||
[CREATE_REPO]: error,
|
||||
},
|
||||
};
|
||||
expect(getCreateRepoFailure(state)).toEqual(error);
|
||||
});
|
||||
|
||||
it('should return undefined when create repo did not fail', () => {
|
||||
expect(getCreateRepoFailure({})).toBe(undefined);
|
||||
});
|
||||
|
||||
// modify
|
||||
|
||||
it('should return true, when modify repo is pending', () => {
|
||||
const state = {
|
||||
pending: {
|
||||
[MODIFY_REPO + '/slarti/fjords']: true,
|
||||
},
|
||||
};
|
||||
|
||||
expect(isModifyRepoPending(state, 'slarti', 'fjords')).toEqual(true);
|
||||
});
|
||||
|
||||
it('should return false, when modify repo is not pending', () => {
|
||||
expect(isModifyRepoPending({}, 'slarti', 'fjords')).toEqual(false);
|
||||
});
|
||||
|
||||
it('should return error, when modify repo failed', () => {
|
||||
const state = {
|
||||
failure: {
|
||||
[MODIFY_REPO + '/slarti/fjords']: error,
|
||||
},
|
||||
};
|
||||
|
||||
expect(getModifyRepoFailure(state, 'slarti', 'fjords')).toEqual(error);
|
||||
});
|
||||
|
||||
it('should return undefined, when modify did not fail', () => {
|
||||
expect(getModifyRepoFailure({}, 'slarti', 'fjords')).toBeUndefined();
|
||||
});
|
||||
|
||||
// delete
|
||||
|
||||
it('should return true, when delete repo is pending', () => {
|
||||
const state = {
|
||||
pending: {
|
||||
[DELETE_REPO + '/slarti/fjords']: true,
|
||||
},
|
||||
};
|
||||
expect(isDeleteRepoPending(state, 'slarti', 'fjords')).toEqual(true);
|
||||
});
|
||||
|
||||
it('should return false, when delete repo is not pending', () => {
|
||||
expect(isDeleteRepoPending({}, 'slarti', 'fjords')).toEqual(false);
|
||||
});
|
||||
|
||||
it('should return error when delete repo did fail', () => {
|
||||
const state = {
|
||||
failure: {
|
||||
[DELETE_REPO + '/slarti/fjords']: error,
|
||||
},
|
||||
};
|
||||
expect(getDeleteRepoFailure(state, 'slarti', 'fjords')).toEqual(error);
|
||||
});
|
||||
|
||||
it('should return undefined when delete repo did not fail', () => {
|
||||
expect(getDeleteRepoFailure({}, 'slarti', 'fjords')).toBe(undefined);
|
||||
});
|
||||
|
||||
it('should return true if the list contains the create link', () => {
|
||||
const state = {
|
||||
repos: {
|
||||
list: repositoryCollection,
|
||||
},
|
||||
};
|
||||
|
||||
expect(isAbleToCreateRepos(state)).toBe(true);
|
||||
});
|
||||
|
||||
it('should return false, if create link is unavailable', () => {
|
||||
const state = {
|
||||
repos: {
|
||||
list: {
|
||||
_links: {},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
expect(isAbleToCreateRepos(state)).toBe(false);
|
||||
});
|
||||
});
|
||||
@@ -1,46 +1,45 @@
|
||||
// @flow
|
||||
import { apiClient } from "@scm-manager/ui-components";
|
||||
import * as types from "../../modules/types";
|
||||
import type {
|
||||
import { apiClient } from '@scm-manager/ui-components';
|
||||
import * as types from '../../modules/types';
|
||||
import {
|
||||
Action,
|
||||
Repository,
|
||||
RepositoryCollection
|
||||
} from "@scm-manager/ui-types";
|
||||
import { isPending } from "../../modules/pending";
|
||||
import { getFailure } from "../../modules/failure";
|
||||
RepositoryCollection,
|
||||
} from '@scm-manager/ui-types';
|
||||
import { isPending } from '../../modules/pending';
|
||||
import { getFailure } from '../../modules/failure';
|
||||
|
||||
export const FETCH_REPOS = "scm/repos/FETCH_REPOS";
|
||||
export const FETCH_REPOS = 'scm/repos/FETCH_REPOS';
|
||||
export const FETCH_REPOS_PENDING = `${FETCH_REPOS}_${types.PENDING_SUFFIX}`;
|
||||
export const FETCH_REPOS_SUCCESS = `${FETCH_REPOS}_${types.SUCCESS_SUFFIX}`;
|
||||
export const FETCH_REPOS_FAILURE = `${FETCH_REPOS}_${types.FAILURE_SUFFIX}`;
|
||||
|
||||
export const FETCH_REPO = "scm/repos/FETCH_REPO";
|
||||
export const FETCH_REPO = 'scm/repos/FETCH_REPO';
|
||||
export const FETCH_REPO_PENDING = `${FETCH_REPO}_${types.PENDING_SUFFIX}`;
|
||||
export const FETCH_REPO_SUCCESS = `${FETCH_REPO}_${types.SUCCESS_SUFFIX}`;
|
||||
export const FETCH_REPO_FAILURE = `${FETCH_REPO}_${types.FAILURE_SUFFIX}`;
|
||||
|
||||
export const CREATE_REPO = "scm/repos/CREATE_REPO";
|
||||
export const CREATE_REPO = 'scm/repos/CREATE_REPO';
|
||||
export const CREATE_REPO_PENDING = `${CREATE_REPO}_${types.PENDING_SUFFIX}`;
|
||||
export const CREATE_REPO_SUCCESS = `${CREATE_REPO}_${types.SUCCESS_SUFFIX}`;
|
||||
export const CREATE_REPO_FAILURE = `${CREATE_REPO}_${types.FAILURE_SUFFIX}`;
|
||||
export const CREATE_REPO_RESET = `${CREATE_REPO}_${types.RESET_SUFFIX}`;
|
||||
|
||||
export const MODIFY_REPO = "scm/repos/MODIFY_REPO";
|
||||
export const MODIFY_REPO = 'scm/repos/MODIFY_REPO';
|
||||
export const MODIFY_REPO_PENDING = `${MODIFY_REPO}_${types.PENDING_SUFFIX}`;
|
||||
export const MODIFY_REPO_SUCCESS = `${MODIFY_REPO}_${types.SUCCESS_SUFFIX}`;
|
||||
export const MODIFY_REPO_FAILURE = `${MODIFY_REPO}_${types.FAILURE_SUFFIX}`;
|
||||
export const MODIFY_REPO_RESET = `${MODIFY_REPO}_${types.RESET_SUFFIX}`;
|
||||
|
||||
export const DELETE_REPO = "scm/repos/DELETE_REPO";
|
||||
export const DELETE_REPO = 'scm/repos/DELETE_REPO';
|
||||
export const DELETE_REPO_PENDING = `${DELETE_REPO}_${types.PENDING_SUFFIX}`;
|
||||
export const DELETE_REPO_SUCCESS = `${DELETE_REPO}_${types.SUCCESS_SUFFIX}`;
|
||||
export const DELETE_REPO_FAILURE = `${DELETE_REPO}_${types.FAILURE_SUFFIX}`;
|
||||
|
||||
const CONTENT_TYPE = "application/vnd.scmm-repository+json;v=2";
|
||||
const CONTENT_TYPE = 'application/vnd.scmm-repository+json;v=2';
|
||||
|
||||
// fetch repos
|
||||
|
||||
const SORT_BY = "sortBy=namespaceAndName";
|
||||
const SORT_BY = 'sortBy=namespaceAndName';
|
||||
|
||||
export function fetchRepos(link: string) {
|
||||
return fetchReposByLink(link);
|
||||
@@ -49,7 +48,7 @@ export function fetchRepos(link: string) {
|
||||
export function fetchReposByPage(link: string, page: number, filter?: string) {
|
||||
if (filter) {
|
||||
return fetchReposByLink(
|
||||
`${link}?page=${page - 1}&q=${decodeURIComponent(filter)}`
|
||||
`${link}?page=${page - 1}&q=${decodeURIComponent(filter)}`,
|
||||
);
|
||||
}
|
||||
return fetchReposByLink(`${link}?page=${page - 1}`);
|
||||
@@ -60,10 +59,10 @@ function appendSortByLink(url: string) {
|
||||
return url;
|
||||
}
|
||||
let urlWithSortBy = url;
|
||||
if (url.includes("?")) {
|
||||
urlWithSortBy += "&";
|
||||
if (url.includes('?')) {
|
||||
urlWithSortBy += '&';
|
||||
} else {
|
||||
urlWithSortBy += "?";
|
||||
urlWithSortBy += '?';
|
||||
}
|
||||
return urlWithSortBy + SORT_BY;
|
||||
}
|
||||
@@ -86,21 +85,21 @@ export function fetchReposByLink(link: string) {
|
||||
|
||||
export function fetchReposPending(): Action {
|
||||
return {
|
||||
type: FETCH_REPOS_PENDING
|
||||
type: FETCH_REPOS_PENDING,
|
||||
};
|
||||
}
|
||||
|
||||
export function fetchReposSuccess(repositories: RepositoryCollection): Action {
|
||||
return {
|
||||
type: FETCH_REPOS_SUCCESS,
|
||||
payload: repositories
|
||||
payload: repositories,
|
||||
};
|
||||
}
|
||||
|
||||
export function fetchReposFailure(err: Error): Action {
|
||||
return {
|
||||
type: FETCH_REPOS_FAILURE,
|
||||
payload: err
|
||||
payload: err,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -110,7 +109,7 @@ export function fetchRepoByLink(repo: Repository) {
|
||||
}
|
||||
|
||||
export function fetchRepoByName(link: string, namespace: string, name: string) {
|
||||
const repoUrl = link.endsWith("/") ? link : link + "/";
|
||||
const repoUrl = link.endsWith('/') ? link : link + '/';
|
||||
return fetchRepo(`${repoUrl}${namespace}/${name}`, namespace, name);
|
||||
}
|
||||
|
||||
@@ -134,9 +133,9 @@ export function fetchRepoPending(namespace: string, name: string): Action {
|
||||
type: FETCH_REPO_PENDING,
|
||||
payload: {
|
||||
namespace,
|
||||
name
|
||||
name,
|
||||
},
|
||||
itemId: namespace + "/" + name
|
||||
itemId: namespace + '/' + name,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -144,23 +143,23 @@ export function fetchRepoSuccess(repository: Repository): Action {
|
||||
return {
|
||||
type: FETCH_REPO_SUCCESS,
|
||||
payload: repository,
|
||||
itemId: createIdentifier(repository)
|
||||
itemId: createIdentifier(repository),
|
||||
};
|
||||
}
|
||||
|
||||
export function fetchRepoFailure(
|
||||
namespace: string,
|
||||
name: string,
|
||||
error: Error
|
||||
error: Error,
|
||||
): Action {
|
||||
return {
|
||||
type: FETCH_REPO_FAILURE,
|
||||
payload: {
|
||||
namespace,
|
||||
name,
|
||||
error
|
||||
error,
|
||||
},
|
||||
itemId: namespace + "/" + name
|
||||
itemId: namespace + '/' + name,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -169,14 +168,14 @@ export function fetchRepoFailure(
|
||||
export function createRepo(
|
||||
link: string,
|
||||
repository: Repository,
|
||||
callback?: (repo: Repository) => void
|
||||
callback?: (repo: Repository) => void,
|
||||
) {
|
||||
return function(dispatch: any) {
|
||||
dispatch(createRepoPending());
|
||||
return apiClient
|
||||
.post(link, repository, CONTENT_TYPE)
|
||||
.then(response => {
|
||||
const location = response.headers.get("Location");
|
||||
const location = response.headers.get('Location');
|
||||
dispatch(createRepoSuccess());
|
||||
return apiClient.get(location);
|
||||
})
|
||||
@@ -194,26 +193,26 @@ export function createRepo(
|
||||
|
||||
export function createRepoPending(): Action {
|
||||
return {
|
||||
type: CREATE_REPO_PENDING
|
||||
type: CREATE_REPO_PENDING,
|
||||
};
|
||||
}
|
||||
|
||||
export function createRepoSuccess(): Action {
|
||||
return {
|
||||
type: CREATE_REPO_SUCCESS
|
||||
type: CREATE_REPO_SUCCESS,
|
||||
};
|
||||
}
|
||||
|
||||
export function createRepoFailure(err: Error): Action {
|
||||
return {
|
||||
type: CREATE_REPO_FAILURE,
|
||||
payload: err
|
||||
payload: err,
|
||||
};
|
||||
}
|
||||
|
||||
export function createRepoReset(): Action {
|
||||
return {
|
||||
type: CREATE_REPO_RESET
|
||||
type: CREATE_REPO_RESET,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -244,7 +243,7 @@ export function modifyRepoPending(repository: Repository): Action {
|
||||
return {
|
||||
type: MODIFY_REPO_PENDING,
|
||||
payload: repository,
|
||||
itemId: createIdentifier(repository)
|
||||
itemId: createIdentifier(repository),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -252,26 +251,31 @@ export function modifyRepoSuccess(repository: Repository): Action {
|
||||
return {
|
||||
type: MODIFY_REPO_SUCCESS,
|
||||
payload: repository,
|
||||
itemId: createIdentifier(repository)
|
||||
itemId: createIdentifier(repository),
|
||||
};
|
||||
}
|
||||
|
||||
export function modifyRepoFailure(
|
||||
repository: Repository,
|
||||
error: Error
|
||||
error: Error,
|
||||
): Action {
|
||||
return {
|
||||
type: MODIFY_REPO_FAILURE,
|
||||
payload: { error, repository },
|
||||
itemId: createIdentifier(repository)
|
||||
payload: {
|
||||
error,
|
||||
repository,
|
||||
},
|
||||
itemId: createIdentifier(repository),
|
||||
};
|
||||
}
|
||||
|
||||
export function modifyRepoReset(repository: Repository): Action {
|
||||
return {
|
||||
type: MODIFY_REPO_RESET,
|
||||
payload: { repository },
|
||||
itemId: createIdentifier(repository)
|
||||
payload: {
|
||||
repository,
|
||||
},
|
||||
itemId: createIdentifier(repository),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -298,7 +302,7 @@ export function deleteRepoPending(repository: Repository): Action {
|
||||
return {
|
||||
type: DELETE_REPO_PENDING,
|
||||
payload: repository,
|
||||
itemId: createIdentifier(repository)
|
||||
itemId: createIdentifier(repository),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -306,32 +310,32 @@ export function deleteRepoSuccess(repository: Repository): Action {
|
||||
return {
|
||||
type: DELETE_REPO_SUCCESS,
|
||||
payload: repository,
|
||||
itemId: createIdentifier(repository)
|
||||
itemId: createIdentifier(repository),
|
||||
};
|
||||
}
|
||||
|
||||
export function deleteRepoFailure(
|
||||
repository: Repository,
|
||||
error: Error
|
||||
error: Error,
|
||||
): Action {
|
||||
return {
|
||||
type: DELETE_REPO_FAILURE,
|
||||
payload: {
|
||||
error,
|
||||
repository
|
||||
repository,
|
||||
},
|
||||
itemId: createIdentifier(repository)
|
||||
itemId: createIdentifier(repository),
|
||||
};
|
||||
}
|
||||
|
||||
// reducer
|
||||
|
||||
function createIdentifier(repository: Repository) {
|
||||
return repository.namespace + "/" + repository.name;
|
||||
return repository.namespace + '/' + repository.name;
|
||||
}
|
||||
|
||||
function normalizeByNamespaceAndName(
|
||||
repositoryCollection: RepositoryCollection
|
||||
repositoryCollection: RepositoryCollection,
|
||||
) {
|
||||
const names = [];
|
||||
const byNames = {};
|
||||
@@ -344,28 +348,30 @@ function normalizeByNamespaceAndName(
|
||||
list: {
|
||||
...repositoryCollection,
|
||||
_embedded: {
|
||||
repositories: names
|
||||
}
|
||||
repositories: names,
|
||||
},
|
||||
},
|
||||
byNames: byNames
|
||||
byNames: byNames,
|
||||
};
|
||||
}
|
||||
|
||||
const reducerByNames = (state: Object, repository: Repository) => {
|
||||
const reducerByNames = (state: object, repository: Repository) => {
|
||||
const identifier = createIdentifier(repository);
|
||||
return {
|
||||
...state,
|
||||
byNames: {
|
||||
...state.byNames,
|
||||
[identifier]: repository
|
||||
}
|
||||
[identifier]: repository,
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
export default function reducer(
|
||||
state: Object = {},
|
||||
action: Action = { type: "UNKNOWN" }
|
||||
): Object {
|
||||
state: object = {},
|
||||
action: Action = {
|
||||
type: 'UNKNOWN',
|
||||
},
|
||||
): object {
|
||||
if (!action.payload) {
|
||||
return state;
|
||||
}
|
||||
@@ -382,7 +388,7 @@ export default function reducer(
|
||||
|
||||
// selectors
|
||||
|
||||
export function getRepositoryCollection(state: Object) {
|
||||
export function getRepositoryCollection(state: object) {
|
||||
if (state.repos && state.repos.list && state.repos.byNames) {
|
||||
const repositories = [];
|
||||
for (let repositoryName of state.repos.list._embedded.repositories) {
|
||||
@@ -391,43 +397,43 @@ export function getRepositoryCollection(state: Object) {
|
||||
return {
|
||||
...state.repos.list,
|
||||
_embedded: {
|
||||
repositories
|
||||
}
|
||||
repositories,
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export function isFetchReposPending(state: Object) {
|
||||
export function isFetchReposPending(state: object) {
|
||||
return isPending(state, FETCH_REPOS);
|
||||
}
|
||||
|
||||
export function getFetchReposFailure(state: Object) {
|
||||
export function getFetchReposFailure(state: object) {
|
||||
return getFailure(state, FETCH_REPOS);
|
||||
}
|
||||
|
||||
export function getRepository(state: Object, namespace: string, name: string) {
|
||||
export function getRepository(state: object, namespace: string, name: string) {
|
||||
if (state.repos && state.repos.byNames) {
|
||||
return state.repos.byNames[namespace + "/" + name];
|
||||
return state.repos.byNames[namespace + '/' + name];
|
||||
}
|
||||
}
|
||||
|
||||
export function isFetchRepoPending(
|
||||
state: Object,
|
||||
state: object,
|
||||
namespace: string,
|
||||
name: string
|
||||
name: string,
|
||||
) {
|
||||
return isPending(state, FETCH_REPO, namespace + "/" + name);
|
||||
return isPending(state, FETCH_REPO, namespace + '/' + name);
|
||||
}
|
||||
|
||||
export function getFetchRepoFailure(
|
||||
state: Object,
|
||||
state: object,
|
||||
namespace: string,
|
||||
name: string
|
||||
name: string,
|
||||
) {
|
||||
return getFailure(state, FETCH_REPO, namespace + "/" + name);
|
||||
return getFailure(state, FETCH_REPO, namespace + '/' + name);
|
||||
}
|
||||
|
||||
export function isAbleToCreateRepos(state: Object) {
|
||||
export function isAbleToCreateRepos(state: object) {
|
||||
return !!(
|
||||
state.repos &&
|
||||
state.repos.list &&
|
||||
@@ -436,50 +442,50 @@ export function isAbleToCreateRepos(state: Object) {
|
||||
);
|
||||
}
|
||||
|
||||
export function isCreateRepoPending(state: Object) {
|
||||
export function isCreateRepoPending(state: object) {
|
||||
return isPending(state, CREATE_REPO);
|
||||
}
|
||||
|
||||
export function getCreateRepoFailure(state: Object) {
|
||||
export function getCreateRepoFailure(state: object) {
|
||||
return getFailure(state, CREATE_REPO);
|
||||
}
|
||||
|
||||
export function isModifyRepoPending(
|
||||
state: Object,
|
||||
state: object,
|
||||
namespace: string,
|
||||
name: string
|
||||
name: string,
|
||||
) {
|
||||
return isPending(state, MODIFY_REPO, namespace + "/" + name);
|
||||
return isPending(state, MODIFY_REPO, namespace + '/' + name);
|
||||
}
|
||||
|
||||
export function getModifyRepoFailure(
|
||||
state: Object,
|
||||
state: object,
|
||||
namespace: string,
|
||||
name: string
|
||||
name: string,
|
||||
) {
|
||||
return getFailure(state, MODIFY_REPO, namespace + "/" + name);
|
||||
return getFailure(state, MODIFY_REPO, namespace + '/' + name);
|
||||
}
|
||||
|
||||
export function isDeleteRepoPending(
|
||||
state: Object,
|
||||
state: object,
|
||||
namespace: string,
|
||||
name: string
|
||||
name: string,
|
||||
) {
|
||||
return isPending(state, DELETE_REPO, namespace + "/" + name);
|
||||
return isPending(state, DELETE_REPO, namespace + '/' + name);
|
||||
}
|
||||
|
||||
export function getDeleteRepoFailure(
|
||||
state: Object,
|
||||
state: object,
|
||||
namespace: string,
|
||||
name: string
|
||||
name: string,
|
||||
) {
|
||||
return getFailure(state, DELETE_REPO, namespace + "/" + name);
|
||||
return getFailure(state, DELETE_REPO, namespace + '/' + name);
|
||||
}
|
||||
|
||||
export function getPermissionsLink(
|
||||
state: Object,
|
||||
state: object,
|
||||
namespace: string,
|
||||
name: string
|
||||
name: string,
|
||||
) {
|
||||
const repo = getRepository(state, namespace, name);
|
||||
return repo && repo._links ? repo._links.permissions.href : undefined;
|
||||
@@ -1,8 +1,6 @@
|
||||
// @flow
|
||||
|
||||
import fetchMock from "fetch-mock";
|
||||
import configureMockStore from "redux-mock-store";
|
||||
import thunk from "redux-thunk";
|
||||
import fetchMock from 'fetch-mock';
|
||||
import configureMockStore from 'redux-mock-store';
|
||||
import thunk from 'redux-thunk';
|
||||
import {
|
||||
FETCH_REPOSITORY_TYPES,
|
||||
FETCH_REPOSITORY_TYPES_FAILURE,
|
||||
@@ -13,91 +11,91 @@ import {
|
||||
getFetchRepositoryTypesFailure,
|
||||
getRepositoryTypes,
|
||||
isFetchRepositoryTypesPending,
|
||||
shouldFetchRepositoryTypes
|
||||
} from "./repositoryTypes";
|
||||
import reducer from "./repositoryTypes";
|
||||
shouldFetchRepositoryTypes,
|
||||
} from './repositoryTypes';
|
||||
import reducer from './repositoryTypes';
|
||||
|
||||
const git = {
|
||||
name: "git",
|
||||
displayName: "Git",
|
||||
name: 'git',
|
||||
displayName: 'Git',
|
||||
_links: {
|
||||
self: {
|
||||
href: "http://localhost:8081/api/v2/repositoryTypes/git"
|
||||
}
|
||||
}
|
||||
href: 'http://localhost:8081/api/v2/repositoryTypes/git',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const hg = {
|
||||
name: "hg",
|
||||
displayName: "Mercurial",
|
||||
name: 'hg',
|
||||
displayName: 'Mercurial',
|
||||
_links: {
|
||||
self: {
|
||||
href: "http://localhost:8081/api/v2/repositoryTypes/hg"
|
||||
}
|
||||
}
|
||||
href: 'http://localhost:8081/api/v2/repositoryTypes/hg',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const svn = {
|
||||
name: "svn",
|
||||
displayName: "Subversion",
|
||||
name: 'svn',
|
||||
displayName: 'Subversion',
|
||||
_links: {
|
||||
self: {
|
||||
href: "http://localhost:8081/api/v2/repositoryTypes/svn"
|
||||
}
|
||||
}
|
||||
href: 'http://localhost:8081/api/v2/repositoryTypes/svn',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const collection = {
|
||||
_embedded: {
|
||||
repositoryTypes: [git, hg, svn]
|
||||
repositoryTypes: [git, hg, svn],
|
||||
},
|
||||
_links: {
|
||||
self: {
|
||||
href: "http://localhost:8081/api/v2/repositoryTypes"
|
||||
}
|
||||
}
|
||||
href: 'http://localhost:8081/api/v2/repositoryTypes',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
describe("repository types caching", () => {
|
||||
it("should fetch repository types, on empty state", () => {
|
||||
describe('repository types caching', () => {
|
||||
it('should fetch repository types, on empty state', () => {
|
||||
expect(shouldFetchRepositoryTypes({})).toBe(true);
|
||||
});
|
||||
|
||||
it("should fetch repository types, if the state contains an empty array", () => {
|
||||
it('should fetch repository types, if the state contains an empty array', () => {
|
||||
const state = {
|
||||
repositoryTypes: []
|
||||
repositoryTypes: [],
|
||||
};
|
||||
expect(shouldFetchRepositoryTypes(state)).toBe(true);
|
||||
});
|
||||
|
||||
it("should not fetch repository types, on pending state", () => {
|
||||
it('should not fetch repository types, on pending state', () => {
|
||||
const state = {
|
||||
pending: {
|
||||
[FETCH_REPOSITORY_TYPES]: true
|
||||
}
|
||||
[FETCH_REPOSITORY_TYPES]: true,
|
||||
},
|
||||
};
|
||||
expect(shouldFetchRepositoryTypes(state)).toBe(false);
|
||||
});
|
||||
|
||||
it("should not fetch repository types, on failure state", () => {
|
||||
it('should not fetch repository types, on failure state', () => {
|
||||
const state = {
|
||||
failure: {
|
||||
[FETCH_REPOSITORY_TYPES]: new Error("no...")
|
||||
}
|
||||
[FETCH_REPOSITORY_TYPES]: new Error('no...'),
|
||||
},
|
||||
};
|
||||
expect(shouldFetchRepositoryTypes(state)).toBe(false);
|
||||
});
|
||||
|
||||
it("should not fetch repository types, if they are already fetched", () => {
|
||||
it('should not fetch repository types, if they are already fetched', () => {
|
||||
const state = {
|
||||
repositoryTypes: [git, hg, svn]
|
||||
repositoryTypes: [git, hg, svn],
|
||||
};
|
||||
expect(shouldFetchRepositoryTypes(state)).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe("repository types fetch", () => {
|
||||
const URL = "/api/v2/repositoryTypes";
|
||||
describe('repository types fetch', () => {
|
||||
const URL = '/api/v2/repositoryTypes';
|
||||
const mockStore = configureMockStore([thunk]);
|
||||
|
||||
afterEach(() => {
|
||||
@@ -105,15 +103,17 @@ describe("repository types fetch", () => {
|
||||
fetchMock.restore();
|
||||
});
|
||||
|
||||
it("should successfully fetch repository types", () => {
|
||||
it('should successfully fetch repository types', () => {
|
||||
fetchMock.getOnce(URL, collection);
|
||||
|
||||
const expectedActions = [
|
||||
{ type: FETCH_REPOSITORY_TYPES_PENDING },
|
||||
{
|
||||
type: FETCH_REPOSITORY_TYPES_PENDING,
|
||||
},
|
||||
{
|
||||
type: FETCH_REPOSITORY_TYPES_SUCCESS,
|
||||
payload: collection
|
||||
}
|
||||
payload: collection,
|
||||
},
|
||||
];
|
||||
|
||||
const store = mockStore({});
|
||||
@@ -122,9 +122,9 @@ describe("repository types fetch", () => {
|
||||
});
|
||||
});
|
||||
|
||||
it("should dispatch FETCH_REPOSITORY_TYPES_FAILURE on server error", () => {
|
||||
it('should dispatch FETCH_REPOSITORY_TYPES_FAILURE on server error', () => {
|
||||
fetchMock.getOnce(URL, {
|
||||
status: 500
|
||||
status: 500,
|
||||
});
|
||||
|
||||
const store = mockStore({});
|
||||
@@ -136,63 +136,63 @@ describe("repository types fetch", () => {
|
||||
});
|
||||
});
|
||||
|
||||
it("should dispatch not dispatch any action, if the repository types are already fetched", () => {
|
||||
it('should dispatch not dispatch any action, if the repository types are already fetched', () => {
|
||||
const store = mockStore({
|
||||
repositoryTypes: [git, hg, svn]
|
||||
repositoryTypes: [git, hg, svn],
|
||||
});
|
||||
store.dispatch(fetchRepositoryTypesIfNeeded());
|
||||
expect(store.getActions().length).toBe(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe("repository types reducer", () => {
|
||||
it("should return unmodified state on unknown action", () => {
|
||||
describe('repository types reducer', () => {
|
||||
it('should return unmodified state on unknown action', () => {
|
||||
const state = [];
|
||||
expect(reducer(state)).toBe(state);
|
||||
});
|
||||
it("should store the repository types on FETCH_REPOSITORY_TYPES_SUCCESS", () => {
|
||||
it('should store the repository types on FETCH_REPOSITORY_TYPES_SUCCESS', () => {
|
||||
const newState = reducer([], fetchRepositoryTypesSuccess(collection));
|
||||
expect(newState).toEqual([git, hg, svn]);
|
||||
});
|
||||
});
|
||||
|
||||
describe("repository types selectors", () => {
|
||||
const error = new Error("The end of the universe");
|
||||
describe('repository types selectors', () => {
|
||||
const error = new Error('The end of the universe');
|
||||
|
||||
it("should return an emtpy array", () => {
|
||||
it('should return an emtpy array', () => {
|
||||
expect(getRepositoryTypes({})).toEqual([]);
|
||||
});
|
||||
|
||||
it("should return the repository types", () => {
|
||||
it('should return the repository types', () => {
|
||||
const state = {
|
||||
repositoryTypes: [git, hg, svn]
|
||||
repositoryTypes: [git, hg, svn],
|
||||
};
|
||||
expect(getRepositoryTypes(state)).toEqual([git, hg, svn]);
|
||||
});
|
||||
|
||||
it("should return true, when fetch repository types is pending", () => {
|
||||
it('should return true, when fetch repository types is pending', () => {
|
||||
const state = {
|
||||
pending: {
|
||||
[FETCH_REPOSITORY_TYPES]: true
|
||||
}
|
||||
[FETCH_REPOSITORY_TYPES]: true,
|
||||
},
|
||||
};
|
||||
expect(isFetchRepositoryTypesPending(state)).toEqual(true);
|
||||
});
|
||||
|
||||
it("should return false, when fetch repos is not pending", () => {
|
||||
it('should return false, when fetch repos is not pending', () => {
|
||||
expect(isFetchRepositoryTypesPending({})).toEqual(false);
|
||||
});
|
||||
|
||||
it("should return error when fetch repository types did fail", () => {
|
||||
it('should return error when fetch repository types did fail', () => {
|
||||
const state = {
|
||||
failure: {
|
||||
[FETCH_REPOSITORY_TYPES]: error
|
||||
}
|
||||
[FETCH_REPOSITORY_TYPES]: error,
|
||||
},
|
||||
};
|
||||
expect(getFetchRepositoryTypesFailure(state)).toEqual(error);
|
||||
});
|
||||
|
||||
it("should return undefined when fetch repos did not fail", () => {
|
||||
it('should return undefined when fetch repos did not fail', () => {
|
||||
expect(getFetchRepositoryTypesFailure({})).toBe(undefined);
|
||||
});
|
||||
});
|
||||
@@ -1,28 +1,20 @@
|
||||
// @flow
|
||||
|
||||
import * as types from "../../modules/types";
|
||||
import type {
|
||||
import * as types from '../../modules/types';
|
||||
import {
|
||||
Action,
|
||||
RepositoryType,
|
||||
RepositoryTypeCollection
|
||||
} from "@scm-manager/ui-types";
|
||||
import { apiClient } from "@scm-manager/ui-components";
|
||||
import { isPending } from "../../modules/pending";
|
||||
import { getFailure } from "../../modules/failure";
|
||||
RepositoryTypeCollection,
|
||||
} from '@scm-manager/ui-types';
|
||||
import { apiClient } from '@scm-manager/ui-components';
|
||||
import { isPending } from '../../modules/pending';
|
||||
import { getFailure } from '../../modules/failure';
|
||||
|
||||
export const FETCH_REPOSITORY_TYPES = "scm/repos/FETCH_REPOSITORY_TYPES";
|
||||
export const FETCH_REPOSITORY_TYPES_PENDING = `${FETCH_REPOSITORY_TYPES}_${
|
||||
types.PENDING_SUFFIX
|
||||
}`;
|
||||
export const FETCH_REPOSITORY_TYPES_SUCCESS = `${FETCH_REPOSITORY_TYPES}_${
|
||||
types.SUCCESS_SUFFIX
|
||||
}`;
|
||||
export const FETCH_REPOSITORY_TYPES_FAILURE = `${FETCH_REPOSITORY_TYPES}_${
|
||||
types.FAILURE_SUFFIX
|
||||
}`;
|
||||
export const FETCH_REPOSITORY_TYPES = 'scm/repos/FETCH_REPOSITORY_TYPES';
|
||||
export const FETCH_REPOSITORY_TYPES_PENDING = `${FETCH_REPOSITORY_TYPES}_${types.PENDING_SUFFIX}`;
|
||||
export const FETCH_REPOSITORY_TYPES_SUCCESS = `${FETCH_REPOSITORY_TYPES}_${types.SUCCESS_SUFFIX}`;
|
||||
export const FETCH_REPOSITORY_TYPES_FAILURE = `${FETCH_REPOSITORY_TYPES}_${types.FAILURE_SUFFIX}`;
|
||||
|
||||
export function fetchRepositoryTypesIfNeeded() {
|
||||
return function(dispatch: any, getState: () => Object) {
|
||||
return function(dispatch: any, getState: () => object) {
|
||||
if (shouldFetchRepositoryTypes(getState())) {
|
||||
return fetchRepositoryTypes(dispatch);
|
||||
}
|
||||
@@ -32,7 +24,7 @@ export function fetchRepositoryTypesIfNeeded() {
|
||||
function fetchRepositoryTypes(dispatch: any) {
|
||||
dispatch(fetchRepositoryTypesPending());
|
||||
return apiClient
|
||||
.get("repositoryTypes")
|
||||
.get('repositoryTypes')
|
||||
.then(response => response.json())
|
||||
.then(repositoryTypes => {
|
||||
dispatch(fetchRepositoryTypesSuccess(repositoryTypes));
|
||||
@@ -42,7 +34,7 @@ function fetchRepositoryTypes(dispatch: any) {
|
||||
});
|
||||
}
|
||||
|
||||
export function shouldFetchRepositoryTypes(state: Object) {
|
||||
export function shouldFetchRepositoryTypes(state: object) {
|
||||
if (
|
||||
isFetchRepositoryTypesPending(state) ||
|
||||
getFetchRepositoryTypesFailure(state)
|
||||
@@ -54,23 +46,23 @@ export function shouldFetchRepositoryTypes(state: Object) {
|
||||
|
||||
export function fetchRepositoryTypesPending(): Action {
|
||||
return {
|
||||
type: FETCH_REPOSITORY_TYPES_PENDING
|
||||
type: FETCH_REPOSITORY_TYPES_PENDING,
|
||||
};
|
||||
}
|
||||
|
||||
export function fetchRepositoryTypesSuccess(
|
||||
repositoryTypes: RepositoryTypeCollection
|
||||
repositoryTypes: RepositoryTypeCollection,
|
||||
): Action {
|
||||
return {
|
||||
type: FETCH_REPOSITORY_TYPES_SUCCESS,
|
||||
payload: repositoryTypes
|
||||
payload: repositoryTypes,
|
||||
};
|
||||
}
|
||||
|
||||
export function fetchRepositoryTypesFailure(error: Error): Action {
|
||||
return {
|
||||
type: FETCH_REPOSITORY_TYPES_FAILURE,
|
||||
payload: error
|
||||
payload: error,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -78,27 +70,29 @@ export function fetchRepositoryTypesFailure(error: Error): Action {
|
||||
|
||||
export default function reducer(
|
||||
state: RepositoryType[] = [],
|
||||
action: Action = { type: "UNKNOWN" }
|
||||
action: Action = {
|
||||
type: 'UNKNOWN',
|
||||
},
|
||||
): RepositoryType[] {
|
||||
if (action.type === FETCH_REPOSITORY_TYPES_SUCCESS && action.payload) {
|
||||
return action.payload._embedded["repositoryTypes"];
|
||||
return action.payload._embedded['repositoryTypes'];
|
||||
}
|
||||
return state;
|
||||
}
|
||||
|
||||
// selectors
|
||||
|
||||
export function getRepositoryTypes(state: Object) {
|
||||
export function getRepositoryTypes(state: object) {
|
||||
if (state.repositoryTypes) {
|
||||
return state.repositoryTypes;
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
||||
export function isFetchRepositoryTypesPending(state: Object) {
|
||||
export function isFetchRepositoryTypesPending(state: object) {
|
||||
return isPending(state, FETCH_REPOSITORY_TYPES);
|
||||
}
|
||||
|
||||
export function getFetchRepositoryTypesFailure(state: Object) {
|
||||
export function getFetchRepositoryTypesFailure(state: object) {
|
||||
return getFailure(state, FETCH_REPOSITORY_TYPES);
|
||||
}
|
||||
Reference in New Issue
Block a user