Skip to content

Commit

Permalink
Merge branch 'improvement/ZENKO-2833-testing-list-buckets-components-…
Browse files Browse the repository at this point in the history
…and-actions' into q/1.0
  • Loading branch information
bert-e committed Oct 12, 2020
2 parents b9cfa16 + 9121973 commit cf5569a
Show file tree
Hide file tree
Showing 6 changed files with 250 additions and 5 deletions.
13 changes: 13 additions & 0 deletions src/js/mock/S3Client.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import type {
import { ApiErrorObject } from './error';

export const ownerName = 'bart';
export const bucketName = 'test';

export const createBucketResponse: CreateBucketResponse = {
Location: '',
Expand All @@ -26,6 +27,10 @@ export class MockS3Client implements S3ClientInterface {
createBucket(): Promise<CreateBucketResponse> {
return Promise.resolve(createBucketResponse);
}

deleteBucket(): Promise<void> {
return Promise.resolve();
}
}

export class ErrorMockS3Client implements S3ClientInterface {
Expand All @@ -38,4 +43,12 @@ export class ErrorMockS3Client implements S3ClientInterface {
createBucket(): Promise<void> {
return Promise.reject(this._error);
}

listBucketsWithLocation(): Promise<void> {
return Promise.reject(this._error);
}

deleteBucket(): Promise<void> {
return Promise.reject(this._error);
}
}
79 changes: 75 additions & 4 deletions src/react/actions/__tests__/s3bucket.test.jsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,40 @@
import * as actions from '../s3bucket';
import * as dispatchAction from './utils/dispatchActionsList';
import {
OWNER_NAME,
errorS3State, initState, testDispatchFunction,
BUCKET_NAME,
OWNER_NAME, errorS3State, initState, testActionFunction, testDispatchErrorTestFn, testDispatchFunction,
} from './utils/testUtil';

const createBucketNetworkAction = dispatchAction.NETWORK_START_ACTION('Creating bucket');
const listBucketsNetworkAction = dispatchAction.NETWORK_START_ACTION('Listing buckets');
const deleteBucketNetworkAction = dispatchAction.NETWORK_START_ACTION('Deleting bucket');

describe('s3bucket actions', () => {
const syncTests = [
{
it: 'should return LIST_BUCKETS_SUCCESS action',
fn: actions.listBucketsSuccess([], OWNER_NAME),
expectedActions: [dispatchAction.LIST_BUCKETS_SUCCESS_ACTION([], OWNER_NAME)],
},
{
it: 'should return OPEN_BUCKET_DELETE_DIALOG action and bucket name',
fn: actions.openBucketDeleteDialog(BUCKET_NAME),
expectedActions: [dispatchAction.OPEN_BUCKET_DELETE_DIALOG_ACTION(BUCKET_NAME)],
},
{
it: 'should return CLOSE_BUCKET_DELETE_DIALOG action',
fn: actions.closeBucketDeleteDialog(),
expectedActions: [dispatchAction.CLOSE_BUCKET_DELETE_DIALOG_ACTION],
},
];

syncTests.forEach(testActionFunction);

const asyncTests = [
{
it: 'createBucket: should return expected actions',
fn: actions.createBucket({
name: 'azeaze',
name: BUCKET_NAME,
locationConstraint: {
value: 'us-east-1',
},
Expand All @@ -31,7 +52,7 @@ describe('s3bucket actions', () => {
{
it: 'createBucket: should handle error',
fn: actions.createBucket({
name: 'azeaze',
name: BUCKET_NAME,
locationConstraint: {
value: 'us-east-1',
},
Expand All @@ -43,7 +64,57 @@ describe('s3bucket actions', () => {
dispatchAction.NETWORK_END_ACTION,
],
},
{
it: 'listBuckets: should return list of buckets',
fn: actions.listBuckets(),
storeState: initState,
expectedActions: [
listBucketsNetworkAction,
dispatchAction.LIST_BUCKETS_SUCCESS_ACTION([], OWNER_NAME),
dispatchAction.NETWORK_END_ACTION,
],
},
{
it: 'deleteBucket: should delete bucket',
fn: actions.deleteBucket(BUCKET_NAME),
storeState: initState,
expectedActions: [
deleteBucketNetworkAction,
listBucketsNetworkAction,
dispatchAction.LIST_BUCKETS_SUCCESS_ACTION([], OWNER_NAME),
dispatchAction.NETWORK_END_ACTION,
dispatchAction.LOCATION_PUSH_ACTION('/buckets'),
dispatchAction.NETWORK_END_ACTION,
dispatchAction.CLOSE_BUCKET_DELETE_DIALOG_ACTION,
],
},
{
it: 'deleteBucket: should handle error',
fn: actions.deleteBucket(BUCKET_NAME),
storeState: errorS3State(),
expectedActions: [
deleteBucketNetworkAction,
dispatchAction.HANDLE_ERROR_MODAL_ACTION('The server is temporarily unavailable.'),
dispatchAction.NETWORK_END_ACTION,
dispatchAction.CLOSE_BUCKET_DELETE_DIALOG_ACTION,
],
},
];

asyncTests.forEach(testDispatchFunction);

testDispatchErrorTestFn({
message: 'S3 Client Api Error Response',
code: 500,
status: 500,
},
{
it: 'listBuckets: should handle error',
fn: actions.listBuckets(),
storeState: errorS3State(),
expectedActions: [
listBucketsNetworkAction,
dispatchAction.NETWORK_END_ACTION,
],
});
});
8 changes: 8 additions & 0 deletions src/react/actions/__tests__/utils/dispatchActionsList.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {

import type {
CloseAccountDeleteDialogAction,
CloseBucketDeleteDialogAction,
CloseLocationDeleteDialogAction,
ConfigAuthFailureAction,
ConfigurationVersionAction,
Expand All @@ -18,6 +19,7 @@ import type {
NetworkActivityEndAction,
NetworkActivityStartAction,
OpenAccountDeleteDialogAction,
OpenBucketDeleteDialogAction,
OpenLocationDeleteDialogAction,
SelectInstanceAction,
SetAppConfigAction,
Expand Down Expand Up @@ -120,3 +122,9 @@ export const CLOSE_LOCATION_DELETE_DIALOG_ACTION: CloseLocationDeleteDialogActio
// * buckets actions
export const LIST_BUCKETS_SUCCESS_ACTION = (list: Array<S3Bucket>, ownerName: string): ListBucketsSuccessAction =>
({ type: 'LIST_BUCKETS_SUCCESS', list: [], ownerName });

export const OPEN_BUCKET_DELETE_DIALOG_ACTION = (bucketName: string): OpenBucketDeleteDialogAction =>
({ type: 'OPEN_BUCKET_DELETE_DIALOG', bucketName });

export const CLOSE_BUCKET_DELETE_DIALOG_ACTION: CloseBucketDeleteDialogAction =
{ type: 'CLOSE_BUCKET_DELETE_DIALOG' };
18 changes: 17 additions & 1 deletion src/react/actions/__tests__/utils/testUtil.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// @flow
import { ErrorMockManagementClient, account, latestOverlay, location } from '../../../../js/mock/managementClient';
import { ErrorMockS3Client, ownerName } from '../../../../js/mock/S3Client';
import { ErrorMockS3Client, bucketName, ownerName } from '../../../../js/mock/S3Client';
import { ErrorUserManager, MockUserManager } from '../../../../js/mock/userManager';
import { ApiErrorObject } from '../../../../js/mock/error';
import type { AppState } from '../../../../types/state';
Expand Down Expand Up @@ -49,6 +49,7 @@ export const LATEST_OVERLAY = latestOverlay;
export const ACCOUNT = account;
export const LOCATION = location;
export const OWNER_NAME = ownerName;
export const BUCKET_NAME = bucketName;

export function errorUserManagerState(): AppState {
const state = initState;
Expand Down Expand Up @@ -180,3 +181,18 @@ export const testDispatchFunction = (test: DispatchTestObject) => {
});
});
};

export const testDispatchErrorTestFn = (error: ApiErrorObject, test: DispatchTestObject) => {
(test.skip ? it.skip : it)(test.it, async () => {
const store = mockStore()(test.storeState);
let testError = null;
try {
await store.dispatch(test.fn);
} catch (e) {
const { message } = e;
testError = message;
}
expect(store.getActions()).toEqual(test.expectedActions);
expect(testError).toEqual(error.message);
});
};
79 changes: 79 additions & 0 deletions src/react/databrowser/buckets/__tests__/BucketList.test.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import BucketList from '../BucketList';
import { List } from 'immutable';
import { MemoryRouter } from 'react-router-dom';
import React from 'react';
import { reduxMount } from '../../../utils/test';

describe('BucketList', () => {
const buckets = List([{
CreationDate: 'Wed Oct 07 2020 16:35:57',
LocationConstraint: 'us-east-1',
Name: 'bucket1',
}, {
CreationDate: 'Wed Oct 07 2020 16:35:57',
LocationConstraint: 'us-east-1',
Name: 'bucket2',
}]);
const selectedBucketName = 'bucket2';

it('should list buckets with the data associated with', () => {
const { component } = reduxMount(
<MemoryRouter>
<BucketList buckets={buckets} locations={{
'us-east-1': {
isBuiltin: true,
locationType: 'location-file-v1',
name: 'us-east-1',
objectId: '',
},
}} selectedBucketName=""/>
</MemoryRouter>,
);

const firstBucketCellLink = component.find('Cell').at(0).find('a');
const firstBucketCellLocation = component.find('Cell').at(1);
const firstBucketCellDate = component.find('Cell').at(2);
expect(firstBucketCellLink.text()).toBe('bucket1');
expect(firstBucketCellLink.prop('href')).toBe('/buckets/bucket1/objects');
expect(firstBucketCellLocation.text()).toBe('us-east-1 / Zenko Local Filesystem');
expect(firstBucketCellDate.text()).toBe('Wed Oct 07 2020 16:35:57');

const secondBucketCellLink = component.find('Cell').at(3).find('a');
const secondBucketCellLocation = component.find('Cell').at(4);
const secondBucketCellDate = component.find('Cell').at(5);
expect(secondBucketCellLink.text()).toBe('bucket2');
expect(secondBucketCellLink.prop('href')).toBe('/buckets/bucket2/objects');
expect(secondBucketCellLocation.text()).toBe('us-east-1 / Zenko Local Filesystem');
expect(secondBucketCellDate.text()).toBe('Wed Oct 07 2020 16:35:57');
});

it('should select row if the bucket name specified in the parameter matches one of the bucket names listed', () => {
const { component } = reduxMount(
<MemoryRouter>
<BucketList buckets={buckets} locations={{}} selectedBucketName={selectedBucketName}/>
</MemoryRouter>,
);

const bucketRows = component.find('Row').children();
bucketRows.forEach(bucketRow => {
if (bucketRow.find('a').text() === selectedBucketName) {
expect(bucketRow.prop('isSelected')).toBe(true);
} else {
expect(bucketRow.prop('isSelected')).toBe(false);
}
});
});

it('should select no row if there is no bucket name specified in the parameter', () => {
const { component } = reduxMount(
<MemoryRouter>
<BucketList buckets={buckets} locations={{}} selectedBucketName=""/>
</MemoryRouter>,
);

const bucketRows = component.find('Row').children();
bucketRows.forEach(bucketRow => {
expect(bucketRow.prop('isSelected')).toBe(false);
});
});
});
58 changes: 58 additions & 0 deletions src/react/databrowser/buckets/__tests__/Buckets.test.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import router, { Redirect } from 'react-router';
import BucketDetails from '../BucketDetails';
import BucketHead from '../BucketHead';
import BucketList from '../BucketList';
import Buckets from '../Buckets';
import { List } from 'immutable';
import { MemoryRouter } from 'react-router-dom';
import { OWNER_NAME } from '../../../actions/__tests__/utils/testUtil';
import React from 'react';
import { reduxMount } from '../../../utils/test';

describe('Buckets', () => {
const buckets = [{
CreationDate: 'Wed Oct 07 2020 16:35:57',
LocationConstraint: 'us-east-1',
Name: 'bucket1',
}, {
CreationDate: 'Wed Oct 07 2020 16:35:57',
LocationConstraint: 'us-east-1',
Name: 'bucket2',
}];

it('should display EmptyStateContainer if no bucket is present', () => {
jest.spyOn(router, 'useParams').mockReturnValue({ bucketName: '' });
const { component } = reduxMount(<Buckets/>);

expect(component.find('Warning').prop('title')).toBe('Create your first bucket.');
});

it('should redirect to the first bucket if no bucket is selected', () => {
jest.spyOn(router, 'useParams').mockReturnValue({ bucketName: '' });
const { component } = reduxMount(<MemoryRouter><Buckets/></MemoryRouter>, {
s3: {
listBucketsResults: {
list: List(buckets),
ownerName: OWNER_NAME,
},
},
});

expect(component.find(Redirect)).toHaveLength(1);
});

it('should render the component', () => {
jest.spyOn(router, 'useParams').mockReturnValue({ bucketName: 'bucket1' });
const { component } = reduxMount(<MemoryRouter><Buckets/></MemoryRouter>, {
s3: {
listBucketsResults: {
list: List(buckets),
},
},
});

expect(component.find(BucketHead)).toHaveLength(1);
expect(component.find(BucketList)).toHaveLength(1);
expect(component.find(BucketDetails)).toHaveLength(1);
});
});

0 comments on commit cf5569a

Please sign in to comment.