Commit 98b72c8a authored by Mark Florian's avatar Mark Florian

Merge branch '208800-step-2-4-mock-server' into 'master'

Setup mock server for IDE integration spec (RUN AS-IF-FOSS)

See merge request gitlab-org/gitlab!37470
parents 5a5cf920 947e747f
......@@ -119,6 +119,15 @@ if (IS_EE) {
});
}
if (!IS_PRODUCTION) {
const fixtureDir = IS_EE ? 'fixtures-ee' : 'fixtures';
Object.assign(alias, {
test_fixtures: path.join(ROOT_PATH, `tmp/tests/frontend/${fixtureDir}`),
test_helpers: path.join(ROOT_PATH, 'spec/frontend_integration/test_helpers'),
});
}
let dll;
if (VENDOR_DLL && !IS_PRODUCTION) {
......
......@@ -40,6 +40,8 @@ module.exports = path => {
'emojis(/.*).json': '<rootDir>/fixtures/emojis$1.json',
'^spec/test_constants$': '<rootDir>/spec/frontend/helpers/test_constants',
'^jest/(.*)$': '<rootDir>/spec/frontend/$1',
'test_helpers(/.*)$': '<rootDir>/spec/frontend_integration/test_helpers$1',
'test_fixtures(/.*)$': '<rootDir>/tmp/tests/frontend/fixtures$1',
};
const collectCoverageFrom = ['<rootDir>/app/assets/javascripts/**/*.{js,vue}'];
......@@ -51,6 +53,7 @@ module.exports = path => {
'^ee_component(/.*)$': rootDirEE,
'^ee_else_ce(/.*)$': rootDirEE,
'^ee_jest/(.*)$': '<rootDir>/ee/spec/frontend/$1',
'test_fixtures(/.*)$': '<rootDir>/tmp/tests/frontend/fixtures-ee$1',
});
collectCoverageFrom.push(rootDirEE.replace('$1', '/**/*.{js,vue}'));
......@@ -75,7 +78,7 @@ module.exports = path => {
cacheDirectory: '<rootDir>/tmp/cache/jest',
modulePathIgnorePatterns: ['<rootDir>/.yarn-cache/'],
reporters,
setupFilesAfterEnv: ['<rootDir>/spec/frontend/test_setup.js', 'jest-canvas-mock'],
setupFilesAfterEnv: [`<rootDir>/${path}/test_setup.js`, 'jest-canvas-mock'],
restoreMocks: true,
transform: {
'^.+\\.(gql|graphql)$': 'jest-transform-graphql',
......
......@@ -51,7 +51,7 @@ class CustomEnvironment extends JSDOMEnvironment {
this.global.fetch = () => {};
// Expose the jsdom (created in super class) to the global so that we can call reconfigure({ url: '' }) to properly set `window.location`
this.global.dom = this.dom;
this.global.jsdom = this.dom;
Object.assign(this.global.performance, {
mark: () => null,
......
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe API::MergeRequests, '(JavaScript fixtures)', type: :request do
include ApiHelpers
include JavaScriptFixturesHelpers
let(:admin) { create(:admin, name: 'root') }
let(:namespace) { create(:namespace, name: 'gitlab-test' )}
let(:project) { create(:project, :repository, namespace: namespace, path: 'lorem-ipsum') }
before(:all) do
clean_frontend_fixtures('api/merge_requests')
end
it 'api/merge_requests/get.json' do
4.times { |i| create(:merge_request, source_project: project, source_branch: "branch-#{i}") }
get api("/projects/#{project.id}/merge_requests", admin)
expect(response).to be_successful
end
end
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe API::Projects, '(JavaScript fixtures)', type: :request do
include ApiHelpers
include JavaScriptFixturesHelpers
let(:admin) { create(:admin, name: 'root') }
let(:namespace) { create(:namespace, name: 'gitlab-test' )}
let(:project) { create(:project, :repository, namespace: namespace, path: 'lorem-ipsum') }
let(:project_empty) { create(:project_empty_repo, namespace: namespace, path: 'lorem-ipsum-empty') }
before(:all) do
clean_frontend_fixtures('api/projects')
end
it 'api/projects/get.json' do
get api("/projects/#{project.id}", admin)
expect(response).to be_successful
end
it 'api/projects/get_empty.json' do
get api("/projects/#{project_empty.id}", admin)
expect(response).to be_successful
end
it 'api/projects/branches/get.json' do
get api("/projects/#{project.id}/repository/branches/#{project.default_branch}", admin)
expect(response).to be_successful
end
end
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe 'Projects JSON endpoints (JavaScript fixtures)', type: :controller do
include JavaScriptFixturesHelpers
let(:admin) { create(:admin, name: 'root') }
let(:project) { create(:project, :repository) }
before(:all) do
clean_frontend_fixtures('projects_json/')
end
before do
project.add_maintainer(admin)
sign_in(admin)
end
describe Projects::FindFileController, '(JavaScript fixtures)', type: :controller do
it 'projects_json/files.json' do
get :list,
params: {
namespace_id: project.namespace.to_param,
project_id: project,
id: project.default_branch
},
format: 'json'
expect(response).to be_successful
end
end
describe Projects::CommitController, '(JavaScript fixtures)', type: :controller do
it 'projects_json/pipelines_empty.json' do
get :pipelines,
params: {
namespace_id: project.namespace.to_param,
project_id: project,
id: project.commit(project.default_branch).id,
format: 'json'
}
expect(response).to be_successful
end
end
end
......@@ -8,32 +8,12 @@
*
* See https://gitlab.com/gitlab-org/gitlab/-/issues/208800 for more information.
*/
import MockAdapter from 'axios-mock-adapter';
import axios from '~/lib/utils/axios_utils';
import { initIde } from '~/ide';
import extendStore from '~/ide/stores/extend';
import { TEST_HOST } from 'helpers/test_constants';
import { useOverclockTimers } from 'test_helpers/utils/overclock_timers';
jest.mock('~/api', () => {
return {
project: jest.fn().mockImplementation(() => new Promise(() => {})),
};
});
jest.mock('~/ide/services/gql', () => {
return {
query: jest.fn().mockImplementation(() => new Promise(() => {})),
};
});
describe('WebIDE', () => {
let vm;
let root;
let mock;
let initData;
let location;
beforeEach(() => {
root = document.createElement('div');
initData = {
const TEST_DATASET = {
emptyStateSvgPath: '/test/empty_state.svg',
noChangesStateSvgPath: '/test/no_changes_state.svg',
committedStateSvgPath: '/test/committed_state.svg',
......@@ -44,57 +24,39 @@ describe('WebIDE', () => {
clientsidePreviewEnabled: 'true',
renderWhitespaceInCode: 'false',
codesandboxBundlerUrl: 'test/codesandbox_bundler',
};
};
mock = new MockAdapter(axios);
mock.onAny('*').reply(() => new Promise(() => {}));
describe('WebIDE', () => {
useOverclockTimers();
let vm;
let root;
beforeEach(() => {
root = document.createElement('div');
document.body.appendChild(root);
location = { pathname: '/-/ide/project/gitlab-test/test', search: '', hash: '' };
Object.defineProperty(window, 'location', {
get() {
return location;
},
global.jsdom.reconfigure({
url: `${TEST_HOST}/-/ide/project/gitlab-test/lorem-ipsum`,
});
});
afterEach(() => {
vm.$destroy();
vm = null;
mock.restore();
root.remove();
});
const createComponent = () => {
const el = document.createElement('div');
Object.assign(el.dataset, initData);
Object.assign(el.dataset, TEST_DATASET);
root.appendChild(el);
vm = initIde(el);
vm = initIde(el, { extendStore });
};
expect.addSnapshotSerializer({
test(value) {
return value instanceof HTMLElement && !value.$_hit;
},
print(element, serialize) {
element.$_hit = true;
element.querySelectorAll('[style]').forEach(el => {
el.$_hit = true;
if (el.style.display === 'none') {
el.textContent = '(jest: contents hidden)';
}
});
return serialize(element)
.replace(/^\s*<!---->$/gm, '')
.replace(/\n\s*\n/gm, '\n');
},
});
it('runs', () => {
createComponent();
return vm.$nextTick().then(() => {
expect(root).toMatchSnapshot();
});
});
});
import { withValues } from '../utils/obj';
import { getCommit } from '../fixtures';
import { createCommitId } from './commit_id';
// eslint-disable-next-line import/prefer-default-export
export const createNewCommit = ({ id = createCommitId(), message }, orig = getCommit()) => {
return withValues(orig, {
id,
short_id: id.substr(0, 8),
message,
title: message,
web_url: orig.web_url.replace(orig.id, id),
parent_ids: [orig.id],
});
};
const COMMIT_ID_LENGTH = 40;
const DEFAULT_COMMIT_ID = Array(COMMIT_ID_LENGTH)
.fill('0')
.join('');
export const createCommitId = (index = 0) =>
`${index}${DEFAULT_COMMIT_ID}`.substr(0, COMMIT_ID_LENGTH);
export const createCommitIdGenerator = () => {
let prevCommitId = 0;
const next = () => {
prevCommitId += 1;
return createCommitId(prevCommitId);
};
return {
next,
};
};
export * from './commit';
export * from './commit_id';
/* eslint-disable global-require */
import { memoize } from 'lodash';
export const getProject = () => require('test_fixtures/api/projects/get.json');
export const getBranch = () => require('test_fixtures/api/projects/branches/get.json');
export const getMergeRequests = () => require('test_fixtures/api/merge_requests/get.json');
export const getRepositoryFiles = () => require('test_fixtures/projects_json/files.json');
export const getPipelinesEmptyResponse = () =>
require('test_fixtures/projects_json/pipelines_empty.json');
export const getCommit = memoize(() => getBranch().commit);
import { buildSchema, graphql } from 'graphql';
import gitlabSchemaStr from '../../../../doc/api/graphql/reference/gitlab_schema.graphql';
const graphqlSchema = buildSchema(gitlabSchemaStr.loc.source.body);
const graphqlResolvers = {
project({ fullPath }, schema) {
const result = schema.projects.findBy({ path_with_namespace: fullPath });
const userPermission = schema.db.userPermissions[0];
return {
...result.attrs,
userPermissions: {
...userPermission,
},
};
},
};
// eslint-disable-next-line import/prefer-default-export
export const graphqlQuery = (query, variables, schema) =>
graphql(graphqlSchema, query, graphqlResolvers, schema, variables);
import { Server, Model, RestSerializer } from 'miragejs';
import { getProject, getBranch, getMergeRequests, getRepositoryFiles } from 'test_helpers/fixtures';
import setupRoutes from './routes';
export const createMockServerOptions = () => ({
models: {
project: Model,
branch: Model,
mergeRequest: Model,
file: Model,
userPermission: Model,
},
serializers: {
application: RestSerializer.extend({
root: false,
}),
},
seeds(schema) {
schema.db.loadData({
files: getRepositoryFiles().map(path => ({ path })),
projects: [getProject()],
branches: [getBranch()],
mergeRequests: getMergeRequests(),
userPermissions: [
{
createMergeRequestIn: true,
readMergeRequest: true,
pushCode: true,
},
],
});
},
routes() {
this.namespace = '';
this.urlPrefix = '/';
setupRoutes(this);
},
});
export const createMockServer = () => {
const server = new Server(createMockServerOptions());
return server;
};
export default server => {
['get', 'post', 'put', 'delete', 'patch'].forEach(method => {
server[method]('*', () => {
return new Response(404);
});
});
};
import { getPipelinesEmptyResponse } from 'test_helpers/fixtures';
export default server => {
server.get('*/commit/:id/pipelines', () => {
return getPipelinesEmptyResponse();
});
server.get('/api/v4/projects/:id/runners', () => {
return [];
});
};
import { graphqlQuery } from '../graphql';
export default server => {
server.post('/api/graphql', (schema, request) => {
const batches = JSON.parse(request.requestBody);
return Promise.all(
batches.map(({ query, variables }) => graphqlQuery(query, variables, schema)),
);
});
};
/* eslint-disable global-require */
export default server => {
[
require('./graphql'),
require('./projects'),
require('./repository'),
require('./ci'),
require('./404'),
].forEach(({ default: setup }) => {
setup(server);
});
};
import { withKeys } from 'test_helpers/utils/obj';
export default server => {
server.get('/api/v4/projects/:id', (schema, request) => {
const { id } = request.params;
const proj =
schema.projects.findBy({ id }) ?? schema.projects.findBy({ path_with_namespace: id });
return proj.attrs;
});
server.get('/api/v4/projects/:id/merge_requests', (schema, request) => {
const result = schema.mergeRequests.where(
withKeys(request.queryParams, {
source_project_id: 'project_id',
source_branch: 'source_branch',
}),
);
return result.models;
});
};
import { createNewCommit, createCommitIdGenerator } from 'test_helpers/factories';
export default server => {
const commitIdGenerator = createCommitIdGenerator();
server.get('/api/v4/projects/:id/repository/branches', schema => {
return schema.db.branches;
});
server.get('/api/v4/projects/:id/repository/branches/:name', (schema, request) => {
const { name } = request.params;
const branch = schema.branches.findBy({ name });
return branch.attrs;
});
server.get('*/-/files/:id', schema => {
return schema.db.files.map(({ path }) => path);
});
server.post('/api/v4/projects/:id/repository/commits', (schema, request) => {
const { branch: branchName, commit_message: message, actions } = JSON.parse(
request.requestBody,
);
const branch = schema.branches.findBy({ name: branchName });
const commit = {
...createNewCommit({ id: commitIdGenerator.next(), message }, branch.attrs.commit),
__actions: actions,
};
branch.update({ commit });
return commit;
});
};
import { createMockServer } from './index';
if (process.env.NODE_ENV === 'development') {
window.mockServer = createMockServer();
}
import '../../../frontend/test_setup';
import './setup_globals';
import './setup_axios';
import './setup_serializers';
import './setup_mock_server';
import axios from '~/lib/utils/axios_utils';
import adapter from 'axios/lib/adapters/xhr';
// We're removing our default axios adapter because this is handled by our mock server now
axios.defaults.adapter = adapter;
import { setTestTimeout } from 'helpers/timeout';
beforeEach(() => {
window.gon = {
api_version: 'v4',
relative_url_root: '',
};
setTestTimeout(5000);
jest.useRealTimers();
});
afterEach(() => {
jest.useFakeTimers();
});
import { createMockServer } from '../mock_server';
beforeEach(() => {
const server = createMockServer();
server.logging = false;
global.mockServer = server;
});
afterEach(() => {
global.mockServer.shutdown();
global.mockServer = null;
});
import defaultSerializer from '../snapshot_serializer';
expect.addSnapshotSerializer(defaultSerializer);
export default {
test(value) {
return value instanceof HTMLElement && !value.$_hit;
},
print(element, serialize) {
element.$_hit = true;
element.querySelectorAll('[style]').forEach(el => {
el.$_hit = true;
if (el.style.display === 'none') {
el.textContent = '(jest: contents hidden)';
}
});
return serialize(element)
.replace(/^\s*<!---->$/gm, '')
.replace(/\n\s*\n/gm, '\n');
},
};
import { has, mapKeys, pick } from 'lodash';
/**
* This method is used to type-safely set values on the given object
*
* @template T
* @returns {T} A shallow copy of `obj`, with the values from `values`
* @throws {Error} If `values` contains a key that isn't already on `obj`
* @param {T} source
* @param {Object} values
*/
export const withValues = (source, values) =>
Object.entries(values).reduce(
(acc, [key, value]) => {
if (!has(acc, key)) {
throw new Error(
`[mock_server] Cannot write property that does not exist on object '${key}'`,
);
}
return {
...acc,
[key]: value,
};
},
{ ...source },
);
/**
* This method returns a subset of the given object and maps the key names based on the
* given `keys`.
*
* @param {Object} obj The source object.
* @param {Object} map The object which contains the keys to use and mapped key names.
*/
export const withKeys = (obj, map) => mapKeys(pick(obj, Object.keys(map)), (val, key) => map[key]);
import { withKeys, withValues } from './obj';
describe('frontend_integration/test_helpers/utils/obj', () => {
describe('withKeys', () => {
it('picks and maps keys', () => {
expect(withKeys({ a: '123', b: 456, c: 'd' }, { b: 'lorem', c: 'ipsum', z: 'zed ' })).toEqual(
{ lorem: 456, ipsum: 'd' },
);
});
});
describe('withValues', () => {
it('sets values', () => {
expect(withValues({ a: '123', b: 456 }, { b: 789 })).toEqual({ a: '123', b: 789 });
});
it('throws if values has non-existent key', () => {
expect(() => withValues({ a: '123', b: 456 }, { b: 789, bogus: 'throws' })).toThrow(
`[mock_server] Cannot write property that does not exist on object 'bogus'`,
);
});
});
});
/**
* This function replaces the existing `setTimeout` and `setInterval` with wrappers that
* discount the `ms` passed in by `boost`.
*
* For example, if a module has:
*
* ```
* setTimeout(cb, 100);
* ```
*
* But a test has:
*
* ```
* useOverclockTimers(25);
* ```
*
* Then the module's call to `setTimeout` effectively becomes:
*
* ```
* setTimeout(cb, 4);
* ```
*
* It's important to note that the timing for `setTimeout` and order of execution is non-deterministic
* and discounting the `ms` passed could make this very obvious and expose some underlying issues
* with flaky failures.
*
* WARNING: If flaky spec failures show up in a spec that is using this helper, please consider either:
*
* - Refactoring the production code so that it's reactive to state changes, not dependent on timers.
* - Removing the call to this helper from the spec.
*
* @param {Number} boost
*/
// eslint-disable-next-line import/prefer-default-export
export const useOverclockTimers = (boost = 50) => {
if (boost <= 0) {
throw new Error(`[overclock_timers] boost (${boost}) cannot be <= 0`);
}
let origSetTimeout;
let origSetInterval;
const newSetTimeout = (fn, msParam = 0) => {
const ms = msParam > 0 ? Math.floor(msParam / boost) : msParam;
return origSetTimeout(fn, ms);
};
const newSetInterval = (fn, msParam = 0) => {
const ms = msParam > 0 ? Math.floor(msParam / boost) : msParam;
return origSetInterval(fn, ms);
};
beforeEach(() => {
origSetTimeout = global.setTimeout;
origSetInterval = global.setInterval;
global.setTimeout = newSetTimeout;
global.setInterval = newSetInterval;
});
afterEach(() => {
global.setTimeout = origSetTimeout;
global.setInterval = origSetInterval;
});
};
import './test_helpers/setup';
......@@ -1044,6 +1044,11 @@
"@types/yargs" "^15.0.0"
chalk "^3.0.0"
"@miragejs/pretender-node-polyfill@^0.1.0":
version "0.1.2"
resolved "https://registry.yarnpkg.com/@miragejs/pretender-node-polyfill/-/pretender-node-polyfill-0.1.2.tgz#d26b6b7483fb70cd62189d05c95d2f67153e43f2"
integrity sha512-M/BexG/p05C5lFfMunxo/QcgIJnMT2vDVCd00wNqK2ImZONIlEETZwWJu1QtLxtmYlSHlCFl3JNzp0tLe7OJ5g==
"@mrmlnc/readdir-enhanced@^2.2.1":
version "2.2.1"
resolved "https://registry.yarnpkg.com/@mrmlnc/readdir-enhanced/-/readdir-enhanced-2.2.1.tgz#524af240d1a360527b730475ecfa1344aa540dde"
......@@ -4903,6 +4908,11 @@ extsprintf@1.3.0, extsprintf@^1.2.0:
resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05"
integrity sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=
fake-xml-http-request@^2.1.1:
version "2.1.1"
resolved "https://registry.yarnpkg.com/fake-xml-http-request/-/fake-xml-http-request-2.1.1.tgz#279fdac235840d7a4dff77d98ec44bce9fc690a6"
integrity sha512-Kn2WYYS6cDBS5jq/voOfSGCA0TafOYAUPbEp8mUVpD/DVV5bQIDjlq+MLLvNUokkbTpjBVlLDaM5PnX+PwZMlw==
fast-deep-equal@^3.1.1:
version "3.1.1"
resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.1.tgz#545145077c501491e33b15ec408c294376e94ae4"
......@@ -6040,6 +6050,11 @@ infer-owner@^1.0.3, infer-owner@^1.0.4:
resolved "https://registry.yarnpkg.com/infer-owner/-/infer-owner-1.0.4.tgz#c4cefcaa8e51051c2a40ba2ce8a3d27295af9467"
integrity sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==
inflected@^2.0.4:
version "2.0.4"
resolved "https://registry.yarnpkg.com/inflected/-/inflected-2.0.4.tgz#323770961ccbe992a98ea930512e9a82d3d3ef77"
integrity sha512-HQPzFLTTUvwfeUH6RAGjD8cHS069mBqXG5n4qaxX7sJXBhVQrsGgF+0ZJGkSuN6a8pcUWB/GXStta11kKi/WvA==
inflight@^1.0.4:
version "1.0.6"
resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9"
......@@ -7601,7 +7616,12 @@ locate-path@^5.0.0:
dependencies:
p-locate "^4.1.0"
lodash.camelcase@4.3.0:
lodash.assign@^4.2.0:
version "4.2.0"
resolved "https://registry.yarnpkg.com/lodash.assign/-/lodash.assign-4.2.0.tgz#0d99f3ccd7a6d261d19bdaeb9245005d285808e7"
integrity sha1-DZnzzNem0mHRm9rrkkUAXShYCOc=
lodash.camelcase@4.3.0, lodash.camelcase@^4.3.0:
version "4.3.0"
resolved "https://registry.yarnpkg.com/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz#b28aa6288a2b9fc651035c7711f65ab6190331a6"
integrity sha1-soqmKIorn8ZRA1x3EfZathkDMaY=
......@@ -7611,6 +7631,11 @@ lodash.clonedeep@^4.5.0:
resolved "https://registry.yarnpkg.com/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz#e23f3f9c4f8fbdde872529c1071857a086e5ccef"
integrity sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=
lodash.compact@^3.0.1:
version "3.0.1"
resolved "https://registry.yarnpkg.com/lodash.compact/-/lodash.compact-3.0.1.tgz#540ce3837745975807471e16b4a2ba21e7256ca5"
integrity sha1-VAzjg3dFl1gHRx4WtKK6IeclbKU=
lodash.differencewith@~4.5.0:
version "4.5.0"
resolved "https://registry.yarnpkg.com/lodash.differencewith/-/lodash.differencewith-4.5.0.tgz#bafafbc918b55154e179176a00bb0aefaac854b7"
......@@ -7621,16 +7646,56 @@ lodash.escaperegexp@^4.1.2:
resolved "https://registry.yarnpkg.com/lodash.escaperegexp/-/lodash.escaperegexp-4.1.2.tgz#64762c48618082518ac3df4ccf5d5886dae20347"
integrity sha1-ZHYsSGGAglGKw99Mz11YhtriA0c=
lodash.flatten@~4.4.0:
lodash.find@^4.6.0:
version "4.6.0"
resolved "https://registry.yarnpkg.com/lodash.find/-/lodash.find-4.6.0.tgz#cb0704d47ab71789ffa0de8b97dd926fb88b13b1"
integrity sha1-ywcE1Hq3F4n/oN6Ll92Sb7iLE7E=
lodash.flatten@^4.4.0, lodash.flatten@~4.4.0:
version "4.4.0"
resolved "https://registry.yarnpkg.com/lodash.flatten/-/lodash.flatten-4.4.0.tgz#f31c22225a9632d2bbf8e4addbef240aa765a61f"
integrity sha1-8xwiIlqWMtK7+OSt2+8kCqdlph8=
lodash.forin@^4.4.0:
version "4.4.0"
resolved "https://registry.yarnpkg.com/lodash.forin/-/lodash.forin-4.4.0.tgz#5d3f20ae564011fbe88381f7d98949c9c9519731"
integrity sha1-XT8grlZAEfvog4H32YlJyclRlzE=
lodash.get@^4.4.2:
version "4.4.2"
resolved "https://registry.yarnpkg.com/lodash.get/-/lodash.get-4.4.2.tgz#2d177f652fa31e939b4438d5341499dfa3825e99"
integrity sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk=
lodash.has@^4.5.2:
version "4.5.2"
resolved "https://registry.yarnpkg.com/lodash.has/-/lodash.has-4.5.2.tgz#d19f4dc1095058cccbe2b0cdf4ee0fe4aa37c862"
integrity sha1-0Z9NwQlQWMzL4rDN9O4P5Ko3yGI=
lodash.invokemap@^4.6.0:
version "4.6.0"
resolved "https://registry.yarnpkg.com/lodash.invokemap/-/lodash.invokemap-4.6.0.tgz#1748cda5d8b0ef8369c4eb3ec54c21feba1f2d62"
integrity sha1-F0jNpdiw74NpxOs+xUwh/rofLWI=
lodash.isempty@^4.4.0:
version "4.4.0"
resolved "https://registry.yarnpkg.com/lodash.isempty/-/lodash.isempty-4.4.0.tgz#6f86cbedd8be4ec987be9aaf33c9684db1b31e7e"
integrity sha1-b4bL7di+TsmHvpqvM8loTbGzHn4=
lodash.isequal@^4.5.0:
version "4.5.0"
resolved "https://registry.yarnpkg.com/lodash.isequal/-/lodash.isequal-4.5.0.tgz#415c4478f2bcc30120c22ce10ed3226f7d3e18e0"
integrity sha1-QVxEePK8wwEgwizhDtMib30+GOA=
lodash.isfunction@^3.0.9:
version "3.0.9"
resolved "https://registry.yarnpkg.com/lodash.isfunction/-/lodash.isfunction-3.0.9.tgz#06de25df4db327ac931981d1bdb067e5af68d051"
integrity sha512-AirXNj15uRIMMPihnkInB4i3NHeb4iBtNg9WRWuK2o31S+ePwwNmDPaTL3o7dTJ+VXNZim7rFs4rxN4YU1oUJw==
lodash.isinteger@^4.0.4:
version "4.0.4"
resolved "https://registry.yarnpkg.com/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz#619c0af3d03f8b04c31f5882840b77b11cd68343"
integrity sha1-YZwK89A/iwTDH1iChAt3sRzWg0M=
lodash.isplainobject@^4.0.6:
version "4.0.6"
resolved "https://registry.yarnpkg.com/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz#7c526a52d89b45c45cc690b88163be0497f550cb"
......@@ -7646,12 +7711,32 @@ lodash.kebabcase@4.1.1:
resolved "https://registry.yarnpkg.com/lodash.kebabcase/-/lodash.kebabcase-4.1.1.tgz#8489b1cb0d29ff88195cceca448ff6d6cc295c36"
integrity sha1-hImxyw0p/4gZXM7KRI/21swpXDY=
lodash.lowerfirst@^4.3.1:
version "4.3.1"
resolved "https://registry.yarnpkg.com/lodash.lowerfirst/-/lodash.lowerfirst-4.3.1.tgz#de3c7b12e02c6524a0059c2f6cb7c5c52655a13d"
integrity sha1-3jx7EuAsZSSgBZwvbLfFxSZVoT0=
lodash.map@^4.6.0:
version "4.6.0"
resolved "https://registry.yarnpkg.com/lodash.map/-/lodash.map-4.6.0.tgz#771ec7839e3473d9c4cde28b19394c3562f4f6d3"
integrity sha1-dx7Hg540c9nEzeKLGTlMNWL09tM=
lodash.mapvalues@^4.6.0:
version "4.6.0"
resolved "https://registry.yarnpkg.com/lodash.mapvalues/-/lodash.mapvalues-4.6.0.tgz#1bafa5005de9dd6f4f26668c30ca37230cc9689c"
integrity sha1-G6+lAF3p3W9PJmaMMMo3IwzJaJw=
lodash.mergewith@^4.6.1:
version "4.6.2"
resolved "https://registry.yarnpkg.com/lodash.mergewith/-/lodash.mergewith-4.6.2.tgz#617121f89ac55f59047c7aec1ccd6654c6590f55"
integrity sha512-GK3g5RPZWTRSeLSpgP8Xhra+pnjBC56q9FZYe1d5RN3TJ35dbkGy3YqBSMbyCrlbi+CM9Z3Jk5yTL7RCsqboyQ==
lodash.snakecase@4.1.1:
lodash.pick@^4.4.0:
version "4.4.0"
resolved "https://registry.yarnpkg.com/lodash.pick/-/lodash.pick-4.4.0.tgz#52f05610fff9ded422611441ed1fc123a03001b3"
integrity sha1-UvBWEP/53tQiYRRB7R/BI6AwAbM=
lodash.snakecase@4.1.1, lodash.snakecase@^4.1.1:
version "4.1.1"
resolved "https://registry.yarnpkg.com/lodash.snakecase/-/lodash.snakecase-4.1.1.tgz#39d714a35357147837aefd64b5dcbb16becd8f8d"
integrity sha1-OdcUo1NXFHg3rv1ktdy7Fr7Nj40=
......@@ -7661,11 +7746,26 @@ lodash.sortby@^4.7.0:
resolved "https://registry.yarnpkg.com/lodash.sortby/-/lodash.sortby-4.7.0.tgz#edd14c824e2cc9c1e0b0a1b42bb5210516a42438"
integrity sha1-7dFMgk4sycHgsKG0K7UhBRakJDg=
lodash.uniq@^4.5.0:
version "4.5.0"
resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773"
integrity sha1-0CJTc662Uq3BvILklFM5qEJ1R3M=
lodash.uniqby@^4.7.0:
version "4.7.0"
resolved "https://registry.yarnpkg.com/lodash.uniqby/-/lodash.uniqby-4.7.0.tgz#d99c07a669e9e6d24e1362dfe266c67616af1302"
integrity sha1-2ZwHpmnp5tJOE2Lf4mbGdhavEwI=
lodash.upperfirst@4.3.1:
version "4.3.1"
resolved "https://registry.yarnpkg.com/lodash.upperfirst/-/lodash.upperfirst-4.3.1.tgz#1365edf431480481ef0d1c68957a5ed99d49f7ce"
integrity sha1-E2Xt9DFIBIHvDRxolXpe2Z1J984=
lodash.values@^4.3.0:
version "4.3.0"
resolved "https://registry.yarnpkg.com/lodash.values/-/lodash.values-4.3.0.tgz#a3a6c2b0ebecc5c2cba1c17e6e620fe81b53d347"
integrity sha1-o6bCsOvsxcLLocF+bmIP6BtT00c=
lodash@^4.0.0, lodash@^4.17.10, lodash@^4.17.11, lodash@^4.17.13, lodash@^4.17.14, lodash@^4.17.15, lodash@~4.17.10:
version "4.17.15"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.15.tgz#b447f6670a0455bbfeedd11392eff330ea097548"
......@@ -8199,6 +8299,38 @@ minipass@^3.0.0, minipass@^3.1.1:
dependencies:
yallist "^4.0.0"
miragejs@^0.1.40:
version "0.1.40"
resolved "https://registry.yarnpkg.com/miragejs/-/miragejs-0.1.40.tgz#5bcba7634312c012748ae7f294e1516b74b37182"
integrity sha512-7zxIcynzdS6425KZ2+TWD6F6DqESorulSDW2QBXf4iKyVn/J5vSielcubAK8sTKUefTPCrSRi7PwgNOb0JlmIg==
dependencies:
"@miragejs/pretender-node-polyfill" "^0.1.0"
inflected "^2.0.4"
lodash.assign "^4.2.0"
lodash.camelcase "^4.3.0"
lodash.clonedeep "^4.5.0"
lodash.compact "^3.0.1"
lodash.find "^4.6.0"
lodash.flatten "^4.4.0"
lodash.forin "^4.4.0"
lodash.get "^4.4.2"
lodash.has "^4.5.2"
lodash.invokemap "^4.6.0"
lodash.isempty "^4.4.0"
lodash.isequal "^4.5.0"
lodash.isfunction "^3.0.9"
lodash.isinteger "^4.0.4"
lodash.isplainobject "^4.0.6"
lodash.lowerfirst "^4.3.1"
lodash.map "^4.6.0"
lodash.mapvalues "^4.6.0"
lodash.pick "^4.4.0"
lodash.snakecase "^4.1.1"
lodash.uniq "^4.5.0"
lodash.uniqby "^4.7.0"
lodash.values "^4.3.0"
pretender "^3.4.3"
mississippi@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/mississippi/-/mississippi-3.0.0.tgz#ea0a3291f97e0b5e8776b363d5f0a12d94c67022"
......@@ -9377,6 +9509,14 @@ prepend-http@^2.0.0:
resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-2.0.0.tgz#e92434bfa5ea8c19f41cdfd401d741a3c819d897"
integrity sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc=
pretender@^3.4.3:
version "3.4.3"
resolved "https://registry.yarnpkg.com/pretender/-/pretender-3.4.3.tgz#a3b4160516007075d29127262f3a0063d19896e9"
integrity sha512-AlbkBly9R8KR+R0sTCJ/ToOeEoUMtt52QVCetui5zoSmeLOU3S8oobFsyPLm1O2txR6t58qDNysqPnA1vVi8Hg==
dependencies:
fake-xml-http-request "^2.1.1"
route-recognizer "^0.3.3"
prettier@1.16.3:
version "1.16.3"
resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.16.3.tgz#8c62168453badef702f34b45b6ee899574a6a65d"
......@@ -10235,6 +10375,11 @@ rope-sequence@^1.2.0:
resolved "https://registry.yarnpkg.com/rope-sequence/-/rope-sequence-1.2.2.tgz#49c4e5c2f54a48e990b050926771e2871bcb31ce"
integrity sha1-ScTlwvVKSOmQsFCSZ3HihxvLMc4=
route-recognizer@^0.3.3:
version "0.3.4"
resolved "https://registry.yarnpkg.com/route-recognizer/-/route-recognizer-0.3.4.tgz#39ab1ffbce1c59e6d2bdca416f0932611e4f3ca3"
integrity sha512-2+MhsfPhvauN1O8KaXpXAOfR/fwe8dnUXVM+xw7yt40lJRfPVQxV6yryZm0cgRvAj5fMF/mdRZbL2ptwbs5i2g==
rsvp@^4.8.4:
version "4.8.4"
resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-4.8.4.tgz#b50e6b34583f3dd89329a2f23a8a2be072845911"
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment