Skip to content

Commit 29dc0f9

Browse files
committed
refactored mock provider to separate package to avoid incidental component registration
1 parent 998ac32 commit 29dc0f9

File tree

16 files changed

+459
-29
lines changed

16 files changed

+459
-29
lines changed

packages/mgt-element/src/index.ts

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,3 @@ export * from './utils/GraphPageIterator';
3030
export * from './utils/LocalizationHelper';
3131
export * from './utils/mgtHtml';
3232
export * from './utils/CustomElement';
33-
34-
export * from './mock/MockProvider';
35-
export * from './mock/mgt-mock-provider';
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
export * from './MockProvider';
2+
export * from './mgt-mock-provider';

packages/mgt/src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,3 +13,4 @@ export * from '@microsoft/mgt-proxy-provider';
1313
export * from '@microsoft/mgt-sharepoint-provider';
1414
export * from '@microsoft/mgt-msal2-provider';
1515
export * from '@microsoft/mgt-teams-msal2-provider';
16+
export * from '@microsoft/mgt-mock-provider';
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
# Microsoft Graph Toolkit Proxy Provider
2+
3+
[![npm](https://img.shields.io/npm/v/@microsoft/mgt-proxy-provider?style=for-the-badge)](https://www.npmjs.com/package/@microsoft/mgt-proxy-provider)
4+
5+
The [Microsoft Graph Toolkit (mgt)](https://aka.ms/mgt) library is a collection of authentication providers and UI components powered by Microsoft Graph.
6+
7+
The `@microsoft/mgt-proxy-provider` package exposes the `ProxyProvider` class which allows a developer to proxy all calls to Microsoft Graph to their own backend. This allows all mgt-components to function properly when the authentication and calls to Microsoft Graph must be done in the backend.
8+
9+
[See docs for full documentation of the ProxyProvider](https://docs.microsoft.com/graph/toolkit/providers/proxy)
10+
11+
## Usage
12+
13+
1. Install the packages
14+
15+
```bash
16+
npm install @microsoft/mgt-element @microsoft/mgt-proxy-provider
17+
```
18+
19+
2. Initialize the provider in code
20+
21+
```ts
22+
import {Providers} from '@microsoft/mgt-element';
23+
import {ProxyProvider} from '@microsoft/mgt-proxy-provider';
24+
25+
// initialize the auth provider globally
26+
Providers.globalProvider = new ProxyProvider("https://myurl.com/api/GraphProxy");
27+
```
28+
29+
3. Alternatively, initialize the provider in html (only `client-id` is required):
30+
31+
```html
32+
<script type="module" src="../node_modules/@microsoft/mgt-proxy-provider/dist/es6/index.js" />
33+
34+
<mgt-proxy-provider graph-proxy-url="https://myurl.com/api/GraphProxy"></mgt-proxy-provider>
35+
```
36+
37+
See [provider usage documentation](https://docs.microsoft.com/graph/toolkit/providers) to learn about how to use the providers with the mgt components, to sign in/sign out, get access tokens, call Microsoft Graph, and more.
38+
39+
## Sea also
40+
* [Microsoft Graph Toolkit docs](https://aka.ms/mgt-docs)
41+
* [Microsoft Graph Toolkit repository](https://aka.ms/mgt)
42+
* [Microsoft Graph Toolkit playground](https://mgt.dev)
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
{
2+
"name": "@microsoft/mgt-mock-provider",
3+
"version": "3.0.0",
4+
"description": "The Microsoft Graph Toolkit Mock Provider",
5+
"keywords": [
6+
"microsoft graph",
7+
"microsoft graph toolkit",
8+
"mgt",
9+
"mock",
10+
"fake",
11+
"stub"
12+
],
13+
"homepage": "https://github.com/microsoftgraph/microsoft-graph-toolkit",
14+
"bugs": {
15+
"url": "https://github.com/microsoftgraph/microsoft-graph-toolkit/issues"
16+
},
17+
"repository": {
18+
"type": "git",
19+
"url": "https://github.com/microsoftgraph/microsoft-graph-toolkit"
20+
},
21+
"author": "Microsoft",
22+
"license": "MIT",
23+
"main": "./dist/es6/index.js",
24+
"types": "./dist/es6/index.d.ts",
25+
"module": "./dist/es6/index.js",
26+
"files": [
27+
"dist",
28+
"src"
29+
],
30+
"scripts": {
31+
"build": "npm run clean && npm run build:compile",
32+
"build:compile": "npm run compile",
33+
"build:watch": "npm run compile:watch",
34+
"clean": "shx rm -rf ./dist && shx rm -rf ./tsconfig.tsbuildinfo",
35+
"compile": "tsc -b",
36+
"compile:watch": "tsc -w",
37+
"lint": "tslint -c ../../../tslint.json 'src/**/*.ts'",
38+
"postpack": "cpx *.tgz ../../../artifacts"
39+
},
40+
"dependencies": {
41+
"@microsoft/mgt-element": "*"
42+
},
43+
"publishConfig": {
44+
"directory": "dist"
45+
}
46+
}
Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
/**
2+
* -------------------------------------------------------------------------------------------
3+
* Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License.
4+
* See License in the project root for license information.
5+
* -------------------------------------------------------------------------------------------
6+
*/
7+
8+
import {
9+
AuthenticationHandler,
10+
Client,
11+
Context,
12+
HTTPMessageHandler,
13+
Middleware,
14+
RetryHandler,
15+
RetryHandlerOptions,
16+
TelemetryHandler
17+
} from '@microsoft/microsoft-graph-client';
18+
import { MgtBaseComponent } from '@microsoft/mgt-element';
19+
import { Graph } from '@microsoft/mgt-element';
20+
import { chainMiddleware } from '@microsoft/mgt-element';
21+
import { MockProvider } from './MockProvider';
22+
23+
/**
24+
* MockGraph Instance
25+
*
26+
* @export
27+
* @class MockGraph
28+
* @extends {Graph}
29+
*/
30+
// tslint:disable-next-line: max-classes-per-file
31+
export class MockGraph extends Graph {
32+
/**
33+
* Creates a new MockGraph instance. Use this static method instead of the constructor.
34+
*
35+
* @static
36+
* @param {MockProvider} provider
37+
* @return {*} {Promise<MockGraph>}
38+
* @memberof MockGraph
39+
*/
40+
public static async create(provider: MockProvider): Promise<MockGraph> {
41+
const middleware: Middleware[] = [
42+
new AuthenticationHandler(provider),
43+
new RetryHandler(new RetryHandlerOptions()),
44+
new TelemetryHandler(),
45+
new MockMiddleware(),
46+
new HTTPMessageHandler()
47+
];
48+
49+
return new MockGraph(
50+
Client.initWithMiddleware({
51+
middleware: chainMiddleware(...middleware),
52+
customHosts: new Set<string>([new URL(await MockMiddleware.getBaseUrl()).hostname])
53+
})
54+
);
55+
}
56+
57+
/**
58+
* Returns an instance of the Graph in the context of the provided component.
59+
*
60+
* @param {MgtBaseComponent} component
61+
* @returns
62+
* @memberof Graph
63+
*/
64+
public forComponent(component: MgtBaseComponent): MockGraph {
65+
// The purpose of the forComponent pattern is to update the headers of any outgoing Graph requests.
66+
// The MockGraph isn't making real Graph requests, so we can simply no-op and return the same instance.
67+
return this;
68+
}
69+
}
70+
71+
/**
72+
* Implements Middleware for the Mock Client to escape
73+
* the graph url from the request
74+
*
75+
* @class MockMiddleware
76+
* @implements {Middleware}
77+
*/
78+
// tslint:disable-next-line: max-classes-per-file
79+
class MockMiddleware implements Middleware {
80+
/**
81+
* @private
82+
* A member to hold next middleware in the middleware chain
83+
*/
84+
private _nextMiddleware: Middleware;
85+
86+
private static _baseUrl;
87+
88+
// tslint:disable-next-line: completed-docs
89+
public async execute(context: Context): Promise<void> {
90+
try {
91+
const baseUrl = await MockMiddleware.getBaseUrl();
92+
context.request = baseUrl + escape(context.request as string);
93+
} catch (error) {
94+
// ignore error
95+
}
96+
return await this._nextMiddleware.execute(context);
97+
}
98+
/**
99+
* Handles setting of next middleware
100+
*
101+
* @param {Middleware} next
102+
* @memberof SdkVersionMiddleware
103+
*/
104+
public setNext(next: Middleware): void {
105+
this._nextMiddleware = next;
106+
}
107+
108+
public static async getBaseUrl() {
109+
if (!this._baseUrl) {
110+
try {
111+
// get the url we should be using from the endpoint service
112+
const response = await fetch('https://cdn.graph.office.net/en-us/graph/api/proxy/endpoint');
113+
this._baseUrl = (await response.json()) + '?url=';
114+
} catch {
115+
// fallback to hardcoded value
116+
this._baseUrl = 'https://proxy.apisandbox.msdn.microsoft.com/svc?url=';
117+
}
118+
}
119+
120+
return this._baseUrl;
121+
}
122+
}
Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
/**
2+
* -------------------------------------------------------------------------------------------
3+
* Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License.
4+
* See License in the project root for license information.
5+
* -------------------------------------------------------------------------------------------
6+
*/
7+
8+
import { IProvider, IProviderAccount, ProviderState } from '@microsoft/mgt-element';
9+
import { MockGraph } from './MockGraph';
10+
11+
/**
12+
* Mock Provider access token for Microsoft Graph APIs
13+
*
14+
* @export
15+
* @class MockProvider
16+
* @extends {IProvider}
17+
*/
18+
export class MockProvider extends IProvider {
19+
// tslint:disable-next-line: completed-docs
20+
public provider: any;
21+
22+
private _mockGraphPromise: Promise<MockGraph>;
23+
24+
/**
25+
* new instance of mock graph provider
26+
*
27+
* @memberof MockProvider
28+
*/
29+
public graph: MockGraph;
30+
constructor(signedIn: boolean = false, signedInAccounts: IProviderAccount[] = []) {
31+
super();
32+
this._mockGraphPromise = MockGraph.create(this);
33+
const enableMultipleLogin = Boolean(signedInAccounts.length);
34+
this.isMultipleAccountSupported = enableMultipleLogin;
35+
this.isMultipleAccountDisabled = !enableMultipleLogin;
36+
this._accounts = signedInAccounts;
37+
38+
this.initializeMockGraph(signedIn);
39+
}
40+
41+
/**
42+
* Indicates if the MockProvider is configured to support multi account mode
43+
* This is only true if the Mock provider has been configured with signedInAccounts in the constructor
44+
*
45+
* @readonly
46+
* @type {boolean}
47+
* @memberof MockProvider
48+
*/
49+
public get isMultiAccountSupportedAndEnabled(): boolean {
50+
return !this.isMultipleAccountDisabled && this.isMultipleAccountSupported;
51+
}
52+
53+
private _accounts: IProviderAccount[] = [];
54+
/**
55+
* Returns the array of accounts the MockProviders has been configured with
56+
*
57+
* @return {*} {IProviderAccount[]}
58+
* @memberof MockProvider
59+
*/
60+
public getAllAccounts?(): IProviderAccount[] {
61+
return this._accounts;
62+
}
63+
64+
/**
65+
* Returns the first account in the set of accounts the MockProvider has been configured with
66+
*
67+
* @return {*} {IProviderAccount}
68+
* @memberof MockProvider
69+
*/
70+
public getActiveAccount?(): IProviderAccount {
71+
if (this._accounts.length) {
72+
return this._accounts[0];
73+
}
74+
}
75+
76+
/**
77+
* sets Provider state to SignedIn
78+
*
79+
* @returns {Promise<void>}
80+
* @memberof MockProvider
81+
*/
82+
public async login(): Promise<void> {
83+
this.setState(ProviderState.Loading);
84+
await this._mockGraphPromise;
85+
await new Promise(resolve => setTimeout(resolve, 3000));
86+
this.setState(ProviderState.SignedIn);
87+
}
88+
89+
/**
90+
* sets Provider state to signed out
91+
*
92+
* @returns {Promise<void>}
93+
* @memberof MockProvider
94+
*/
95+
public async logout(): Promise<void> {
96+
this.setState(ProviderState.Loading);
97+
await this._mockGraphPromise;
98+
await new Promise(resolve => setTimeout(resolve, 3000));
99+
this.setState(ProviderState.SignedOut);
100+
}
101+
102+
/**
103+
* Promise returning token from graph.microsoft.com
104+
*
105+
* @returns {Promise<string>}
106+
* @memberof MockProvider
107+
*/
108+
public getAccessToken(): Promise<string> {
109+
return Promise.resolve('{token:https://graph.microsoft.com/}');
110+
}
111+
112+
/**
113+
* Name used for analytics
114+
*
115+
* @readonly
116+
* @memberof IProvider
117+
*/
118+
public get name() {
119+
return 'MgtMockProvider';
120+
}
121+
122+
private async initializeMockGraph(signedIn: boolean = false) {
123+
this.graph = await this._mockGraphPromise;
124+
125+
if (signedIn) {
126+
this.setState(ProviderState.SignedIn);
127+
} else {
128+
this.setState(ProviderState.SignedOut);
129+
}
130+
}
131+
}
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
export * from './MockProvider';
2+
export * from './mgt-mock-provider';

0 commit comments

Comments
 (0)