Open books from Github (#10670)

* Add open book option in UI

* Add dropdowns option on dialog

* Add flow logic

* Fetch releases and validate URL

* Add class for github books and shared file books

* Change code structure

* Unblock local copy + stack overflows

* Download books from github

* Remove unused files

* Clean code and use the openNotebookFolder command to open remote book

* Checkpoint

* Refactor remote book dialog model to only hold data

* Remove ApiWrapper and refactor createlocalcopy method

* Use sinon js framework instead of typemoq for testing remotebookController

* Remove api wrapper

* Add some tests

* Add more tests and address pr comments

* Address PR comments

* Fix remotebook broken tests

* Add download location in output channel and use openBook command

* Address PR comments

* Fix typos, print error message and remove failing test

* Print error message

* Separate tests in different files

* Declare controller variable inside extension.tst

Co-authored-by: chlafreniere <hichise@gmail.com>
This commit is contained in:
Barbara Valdez
2020-07-24 19:39:03 -07:00
committed by GitHub
parent 56d1a1c1af
commit 6d9efbd603
17 changed files with 866 additions and 8 deletions

View File

@@ -0,0 +1,121 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { RemoteBookDialogModel } from '../../dialog/remoteBookDialogModel';
import { IRelease, RemoteBookController } from '../../book/remoteBookController';
import * as should from 'should';
import * as request from 'request';
import * as sinon from 'sinon';
import * as vscode from 'vscode';
import { MockExtensionContext } from '../common/stubs';
import { AppContext } from '../../common/appContext';
import * as loc from '../../common/localizedConstants';
describe('Remote Book Controller', function () {
let mockExtensionContext: vscode.ExtensionContext = new MockExtensionContext();
let appContext = new AppContext(mockExtensionContext);
let model = new RemoteBookDialogModel();
let controller = new RemoteBookController(model, appContext.outputChannel);
let getStub : sinon.SinonStub;
beforeEach(function (): void {
getStub = sinon.stub(request, 'get');
});
afterEach(function (): void {
sinon.restore();
});
it('Verify that errorMessage is thrown, when fetchReleases call returns empty', async function (): Promise<void> {
let expectedBody = JSON.stringify([]);
let expectedURL = new URL('https://api.github.com/repos/microsoft/test/releases');
getStub.yields(null, { statusCode: 200 }, expectedBody);
try {
await controller.getReleases(expectedURL);
}
catch (err) {
should(err.message).be.equals(loc.msgReleaseNotFound);
should(model.releases.length).be.equal(0);
}
});
it('Should get the books', async function (): Promise<void> {
let expectedBody = JSON.stringify([
{
url: 'https://api.github.com/repos/microsoft/test/releases/1/assets/1',
name: 'test-1.1-EN.zip',
browser_download_url: 'https://api.github.com/repos/microsoft/test/releases/download/1/test-1.1-EN.zip',
},
{
url: 'https://api.github.com/repos/microsoft/test/releases/1/assets/2',
name: 'test-1.1-ES.zip',
browser_download_url: 'https://api.github.com/repos/microsoft/test/releases/download/2/test-1.1-ES.zip',
},
{
url: 'https://api.github.com/repos/microsoft/test/releases/1/assets/1',
name: 'test-1.1-EN.tgz',
browser_download_url: 'https://api.github.com/repos/microsoft/test/releases/download/1/test-1.1-EN.tgz',
},
{
url: 'https://api.github.com/repos/microsoft/test/releases/1/assets/2',
name: 'test-1.1-ES.tar.gz',
browser_download_url: 'https://api.github.com/repos/microsoft/test/releases/download/2/test-1.1-ES.tar.gz',
},
{
url: 'https://api.github.com/repos/microsoft/test/releases/1/assets/3',
name: 'test-1.1-FR.tgz',
browser_download_url: 'https://api.github.com/repos/microsoft/test/releases/download/1/test-1.1-FR.tgz',
}
]);
let expectedURL = new URL('https://api.github.com/repos/microsoft/test/releases/1/assets');
let expectedRelease: IRelease = {
name: 'Test Release',
assetsUrl: expectedURL
};
getStub.yields(null, { statusCode: 200 }, expectedBody);
let result = await controller.getAssets(expectedRelease);
should(result.length).be.above(0, 'Result should contain assets');
result.forEach(asset => {
should(asset).have.property('name');
should(asset).have.property('url');
should(asset).have.property('browserDownloadUrl');
});
});
it('Should throw an error if the book object does not follow the name-version-lang format', async function (): Promise<void> {
let expectedBody = JSON.stringify([
{
url: 'https://api.github.com/repos/microsoft/test/releases/1/assets/1',
name: 'test-1.1.zip',
browser_download_url: 'https://api.github.com/repos/microsoft/test/releases/download/1/test-1.1.zip',
},
{
url: 'https://api.github.com/repos/microsoft/test/releases/1/assets/2',
name: 'test-1.2.zip',
browser_download_url: 'https://api.github.com/repos/microsoft/test/releases/download/1/test-1.2.zip',
},
]);
let expectedURL = new URL('https://api.github.com/repos/microsoft/test/releases/1/assets');
let expectedRelease: IRelease = {
name: 'Test Release',
assetsUrl: expectedURL
};
getStub.yields(null, { statusCode: 200 }, expectedBody);
try {
await controller.getAssets(expectedRelease);
}
catch (err) {
should(err.message).be.equals(loc.msgBookNotFound);
should(model.releases.length).be.equal(0);
}
});
});

View File

@@ -0,0 +1,29 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { RemoteBookDialog } from '../../dialog/remoteBookDialog';
import { RemoteBookDialogModel } from '../../dialog/remoteBookDialogModel';
import { RemoteBookController } from '../../book/remoteBookController';
import * as sinon from 'sinon';
import * as vscode from 'vscode';
import { MockExtensionContext } from '../common/stubs';
import { AppContext } from '../../common/appContext';
import * as azdata from 'azdata';
import * as should from 'should';
describe('Add Remote Book Dialog', function () {
let mockExtensionContext: vscode.ExtensionContext = new MockExtensionContext();
let appContext = new AppContext(mockExtensionContext);
let model = new RemoteBookDialogModel();
let controller = new RemoteBookController(model, appContext.outputChannel);
let dialog = new RemoteBookDialog(controller);
it('Should open dialog successfully ', async function (): Promise<void> {
const spy = sinon.spy(azdata.window, 'openDialog');
await dialog.createDialog();
should(spy.calledOnce).be.true();
});
});

View File

@@ -334,7 +334,7 @@ class TestComponentBase implements azdata.Component {
}
}
class TestDropdownComponent extends TestComponentBase implements azdata.DropDownComponent {
export class TestDropdownComponent extends TestComponentBase implements azdata.DropDownComponent {
constructor(private onClick: vscode.EventEmitter<any>) {
super();
}