Skip to content
Permalink
Browse files

feat: implement did scope

  • Loading branch information...
paulobmarcos authored and satazor committed Apr 17, 2019
1 parent e81e800 commit 05a9715990bc2772a1e534f532214cdf69c88548

Large diffs are not rendered by default.

@@ -81,7 +81,9 @@
"standard-version": "^5.0.0"
},
"dependencies": {
"did-ipid": "^0.1.0",
"hex-array": "^1.0.0",
"ipfs": "^0.35.0",
"normalize-value": "^1.0.1",
"pico-signals": "^1.0.0",
"scrypt-async": "^2.0.1",
@@ -1,14 +1,25 @@
import Ipfs from 'ipfs';
import createWallet from '../index';
import createStorage from '../storage';
import createLocker from '../locker';
import createDid from '../did';
import { mockIpfs } from './mocks';

jest.mock('../storage', () => jest.fn());
jest.mock('../locker', () => jest.fn());
jest.mock('ipfs', () => jest.fn((...args) => new mockIpfs(...args))); // eslint-disable-line babel/new-cap
jest.mock('../storage');
jest.mock('../locker');
jest.mock('../did');

beforeEach(() => {
jest.clearAllMocks();
});

it('should create wallet successfully', async () => {
const wallet = await createWallet();

expect(Object.keys(wallet)).toEqual(['storage', 'locker']);
expect(Object.keys(wallet)).toEqual(['storage', 'locker', 'did']);
expect(Ipfs).toHaveBeenCalledTimes(1);
expect(Ipfs).toHaveBeenCalledWith({ pass: 'K52XQ7K0FPR1DF01RM0L' });
});

it('should throw if storage creation fails', async () => {
@@ -22,3 +33,45 @@ it('should throw if locker creation fails', async () => {

expect(createWallet()).rejects.toThrow('bar');
});

it('should throw if did creation fails', async () => {
createDid.mockImplementationOnce(() => { throw new Error('biz'); });

expect(createWallet()).rejects.toThrow('biz');
});

it('should throw if ipfs node creation fails', async () => {
expect.assertions(2);

Ipfs.mockImplementationOnce(jest.fn(() => ({
on: (state, callback) => { state === 'error' && callback('foobar'); },
})));

try {
await createWallet();
} catch (err) {
expect(err).toEqual('foobar');
}
});

it('should use a ipfs node provided in options', async () => {
const mockIpfsNode = { isOnline: jest.fn(() => true) };

await createWallet({ ipfs: mockIpfsNode });

expect(createDid).toHaveBeenCalledWith(mockIpfsNode);
});

it('should fail if provided ipfs node is not online', async () => {
expect.assertions(2);

const mockIpfsNode = { isOnline: jest.fn(() => false) };

try {
await createWallet({ ipfs: mockIpfsNode });
} catch (err) {
expect(err.message).toEqual('IPFS node is unavailable.');
expect(err.code).toEqual('IPFS_UNAVAILABLE');
}
});

@@ -0,0 +1,13 @@
export class mockIpfs {
constructor(options) {
const { pass } = { ...options };

this.pass = pass;
}

on(state, callback) {
if (state === 'ready') {
callback();
}
}
}
@@ -0,0 +1,10 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`getMethods should return all available methods and its information 1`] = `
Array [
Object {
"description": "The Interplanetary Identifiers DID method",
"method": "ipid",
},
]
`;
@@ -0,0 +1,238 @@
import createIpid from '../methods/ipid';
import createDid from '../index';
import { mockDocument, mockIpid } from './mocks';

jest.mock('../methods/ipid', () => jest.fn(() => mockIpid));

beforeEach(() => {
jest.clearAllMocks();
});

it('should have all specification methods', async () => {
const did = createDid();

expect(typeof did.resolve).toEqual('function');
expect(typeof did.create).toEqual('function');
expect(typeof did.update).toEqual('function');
expect(typeof did.isPublicKeyValid).toEqual('function');
expect(typeof did.getMethods).toEqual('function');
});

describe('getMethods', () => {
it('should return all available methods and its information', async () => {
const did = createDid();

expect(did.getMethods()).toMatchSnapshot();
});
});

describe('resolve', () => {
it('should resolve successfully', async () => {
const did = createDid();
const document = await did.resolve('did:ipid:foo');

expect(mockIpid.resolve).toHaveBeenCalledTimes(1);
expect(mockIpid.resolve).toHaveBeenCalledWith('did:ipid:foo');
expect(document).toEqual(mockDocument);
});

it('should fail if invalid did', async () => {
expect.assertions(2);

const did = createDid();

try {
await did.resolve('did#abcdef');
} catch (err) {
expect(err.message).toEqual('Invalid DID: did#abcdef');
expect(err.code).toEqual('INVALID_DID');
}
});

it('should fail if method is not supported', async () => {
expect.assertions(2);

const did = createDid();

try {
await did.resolve('did:fake:abcdef');
} catch (err) {
expect(err.message).toEqual('Did method `fake` is not supported');
expect(err.code).toEqual('UNSUPPORTED_DID_METHOD');
}
});

it('should fail if method does not support purpose', async () => {
const mockIpidOnce = { ...mockIpid, resolve: undefined };

createIpid.mockImplementationOnce(jest.fn(() => mockIpidOnce));

expect.assertions(2);

const did = createDid();

try {
await did.resolve('did:ipid:abcdef');
} catch (err) {
expect(err.message).toEqual('Purpose `resolve` is not currently supported for `ipid`');
expect(err.code).toEqual('UNSUPPORTED_DID_METHOD_PURPOSE');
}
});
});

describe('create', () => {
it('should create successfully', async () => {
const mockParams = { privateKey: 'mockPrivateKey', foo: 'bar' };
const mockOperations = jest.fn();

const did = createDid();
const document = await did.create('ipid', mockParams, mockOperations);

expect(mockIpid.create).toHaveBeenCalledTimes(1);
expect(mockIpid.create).toHaveBeenCalledWith(mockParams, mockOperations);
expect(document).toEqual(mockDocument);
});

it('should fail if method is not supported', async () => {
expect.assertions(2);

const did = createDid();

try {
await did.create('fake');
} catch (err) {
expect(err.message).toEqual('Did method `fake` is not supported');
expect(err.code).toEqual('UNSUPPORTED_DID_METHOD');
}
});

it('should fail if method does not support purpose', async () => {
const mockIpidOnce = { ...mockIpid, create: undefined };

createIpid.mockImplementationOnce(jest.fn(() => mockIpidOnce));

expect.assertions(2);

const did = createDid();

try {
await did.create('ipid');
} catch (err) {
expect(err.message).toEqual('Purpose `create` is not currently supported for `ipid`');
expect(err.code).toEqual('UNSUPPORTED_DID_METHOD_PURPOSE');
}
});
});

describe('update', () => {
it('should create successfully', async () => {
const mockParams = { privateKey: 'mockPrivateKey', foo: 'bar' };
const mockOperations = jest.fn();

const did = createDid();
const document = await did.update('did:ipid:abcdef', mockParams, mockOperations);

expect(mockIpid.update).toHaveBeenCalledTimes(1);
expect(mockIpid.update).toHaveBeenCalledWith('did:ipid:abcdef', mockParams, mockOperations);
expect(document).toEqual(mockDocument);
});

it('should fail if invalid did', async () => {
expect.assertions(2);

const did = createDid();

try {
await did.update('did#abcdef');
} catch (err) {
expect(err.message).toEqual('Invalid DID: did#abcdef');
expect(err.code).toEqual('INVALID_DID');
}
});

it('should fail if method is not supported', async () => {
expect.assertions(2);

const did = createDid();

try {
await did.update('did:fake:abcdef');
} catch (err) {
expect(err.message).toEqual('Did method `fake` is not supported');
expect(err.code).toEqual('UNSUPPORTED_DID_METHOD');
}
});

it('should fail if method does not support purpose', async () => {
const mockIpidOnce = { ...mockIpid, update: undefined };

createIpid.mockImplementationOnce(jest.fn(() => mockIpidOnce));

expect.assertions(2);

const did = createDid();

try {
await did.update('did:ipid:abcdef');
} catch (err) {
expect(err.message).toEqual('Purpose `update` is not currently supported for `ipid`');
expect(err.code).toEqual('UNSUPPORTED_DID_METHOD_PURPOSE');
}
});
});

describe('isPublicKeyValid', () => {
it('should be successful if public key in document', async () => {
const mockOptions = { foo: 'bar' };

const did = createDid();
const isValid = await did.isPublicKeyValid('did:ipid:abcdef', 'did:ipid:abcdef#123', mockOptions);

expect(isValid).toBeTruthy();
expect(mockIpid.isPublicKeyValid).toHaveBeenCalledTimes(1);
expect(mockIpid.isPublicKeyValid).toHaveBeenCalledWith('did:ipid:abcdef', 'did:ipid:abcdef#123', mockOptions);
});

it('should fail if invalid did', async () => {
expect.assertions(2);

const did = createDid();

try {
await did.isPublicKeyValid('did#abcdef');
} catch (err) {
expect(err.message).toEqual('Invalid DID: did#abcdef');
expect(err.code).toEqual('INVALID_DID');
}
});

it('should fail if method is not supported', async () => {
expect.assertions(2);

const did = createDid();

try {
await did.isPublicKeyValid('did:fake:abcdef');
} catch (err) {
expect(err.message).toEqual('Did method `fake` is not supported');
expect(err.code).toEqual('UNSUPPORTED_DID_METHOD');
}
});

it('should fail if method does not support purpose', async () => {
const mockIpidOnce = { ...mockIpid, isPublicKeyValid: undefined };

createIpid.mockImplementationOnce(jest.fn(() => mockIpidOnce));

expect.assertions(2);

const did = createDid();

try {
await did.isPublicKeyValid('did:ipid:abcdef');
} catch (err) {
expect(err.message).toEqual('Purpose `isPublicKeyValid` is not currently supported for `ipid`');
expect(err.code).toEqual('UNSUPPORTED_DID_METHOD_PURPOSE');
}
});
});
@@ -0,0 +1,19 @@
export const mockDocument = {
'@context': 'https://w3id.org/did/v1',
id: 'did:ipid:QmUTE4cxTxihntPEFqTprgbqyyS9YRaRcC8FXp6PACEjFG',
created: '2019-03-19T16:52:44.948Z',
updated: '2019-03-19T16:53:56.463Z',
};

export const mockIpid = {
constructor: {
info: {
method: 'ipid',
description: 'The Interplanetary Identifiers DID method',
},
},
resolve: jest.fn(() => mockDocument),
create: jest.fn(() => mockDocument),
update: jest.fn(() => mockDocument),
isPublicKeyValid: jest.fn(() => true),
};

0 comments on commit 05a9715

Please sign in to comment.
You can’t perform that action at this time.