diff --git a/sdk/appconfiguration/app-configuration/CHANGELOG.md b/sdk/appconfiguration/app-configuration/CHANGELOG.md index a195cd64a9c0..5107c0de71bb 100644 --- a/sdk/appconfiguration/app-configuration/CHANGELOG.md +++ b/sdk/appconfiguration/app-configuration/CHANGELOG.md @@ -1,7 +1,8 @@ # Release History -## 1.0.2 (Unreleased) +## 1.1.0 (Unreleased) +- Adding browser support for the latest versions of Chrome, Edge and Firefox. ## 1.0.1 (2020-02-19) @@ -18,6 +19,7 @@ This release marks the general availability of the `@azure/app-configuration` pa - Allow developers to prepend additional information to the user agent header. Example: + ```typescript new AppConfigurationClient(connectionString, { userAgentOptions: { @@ -28,7 +30,6 @@ This release marks the general availability of the `@azure/app-configuration` pa ## 1.0.0-preview.10 (2019-12-10) - - Specifying filters for listConfigurationSettings() or listRevisions() is now done with the `keyFilter` or `labelFilter` strings rather than `keys` and `labels` as they were previously. diff --git a/sdk/appconfiguration/app-configuration/karma.conf.js b/sdk/appconfiguration/app-configuration/karma.conf.js new file mode 100644 index 000000000000..4c1b8d1316a5 --- /dev/null +++ b/sdk/appconfiguration/app-configuration/karma.conf.js @@ -0,0 +1,134 @@ +// https://github.com/karma-runner/karma-chrome-launcher +process.env.CHROME_BIN = require("puppeteer").executablePath(); +require("dotenv").config(); + +module.exports = function(config) { + config.set({ + // base path that will be used to resolve all patterns (eg. files, exclude) + basePath: "./", + + // frameworks to use + // available frameworks: https://npmjs.org/browse/keyword/karma-adapter + frameworks: ["mocha"], + + plugins: [ + "karma-mocha", + "karma-mocha-reporter", + "karma-chrome-launcher", + "karma-edge-launcher", + "karma-firefox-launcher", + "karma-ie-launcher", + "karma-env-preprocessor", + "karma-coverage", + "karma-remap-istanbul", + "karma-junit-reporter" + ], + + // list of files / patterns to load in the browser + files: [ + // polyfill service supporting IE11 missing features + // Promise,String.prototype.startsWith,String.prototype.endsWith,String.prototype.repeat,String.prototype.includes,Array.prototype.includes,Object.keys + "https://cdn.polyfill.io/v2/polyfill.js?features=Promise,String.prototype.startsWith,String.prototype.endsWith,String.prototype.repeat,String.prototype.includes,Array.prototype.includes,Object.keys|always", + "test-browser/index.js", + { pattern: "test-browser/index.js.map", type: "html", included: false, served: true } + ], + + // list of files / patterns to exclude + exclude: [], + + // preprocess matching files before serving them to the browser + // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor + preprocessors: { + "**/*.js": ["env"] + // IMPORTANT: COMMENT following line if you want to debug in your browsers!! + // Preprocess source file to calculate code coverage, however this will make source file unreadable + // "test-browser/index.js": ["coverage"] + }, + + // inject following environment values into browser testing with window.__env__ + // environment values MUST be exported or set with same console running "karma start" + // https://www.npmjs.com/package/karma-env-preprocessor + envPreprocessor: [ + "AZ_CONFIG_CONNECTION", + "AZURE_CLIENT_ID", + "AZURE_CLIENT_SECRET", + "AZURE_TENANT_ID", + "TEST_MODE" + ], + + // test results reporter to use + // possible values: 'dots', 'progress' + // available reporters: https://npmjs.org/browse/keyword/karma-reporter + reporters: ["mocha", "coverage", "karma-remap-istanbul", "junit"], + + coverageReporter: { + // specify a common output directory + dir: "coverage-browser/", + reporters: [{ type: "json", subdir: ".", file: "coverage.json" }] + }, + + remapIstanbulReporter: { + src: "coverage-browser/coverage.json", + reports: { + lcovonly: "coverage-browser/lcov.info", + html: "coverage-browser/html/report", + "text-summary": null, + cobertura: "./coverage-browser/cobertura-coverage.xml" + } + }, + + junitReporter: { + outputDir: "", // results will be saved as $outputDir/$browserName.xml + outputFile: "test-results.browser.xml", // if included, results will be saved as $outputDir/$browserName/$outputFile + suite: "", // suite will become the package name attribute in xml testsuite element + useBrowserName: false, // add browser name to report and classes names + nameFormatter: undefined, // function (browser, result) to customize the name attribute in xml testcase element + classNameFormatter: undefined, // function (browser, result) to customize the classname attribute in xml testcase element + properties: {} // key value pair of properties to add to the section of the report + }, + + // web server port + port: 9876, + + // enable / disable colors in the output (reporters and logs) + colors: true, + + // level of logging + // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG + logLevel: config.LOG_INFO, + + // enable / disable watching file and executing tests whenever any file changes + autoWatch: false, + + // start these browsers + // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher + // 'ChromeHeadless', 'Chrome', 'Firefox', 'Edge', 'IE' + browsers: ["ChromeHeadlessNoSandbox"], + customLaunchers: { + ChromeHeadlessNoSandbox: { + base: "ChromeHeadless", + flags: ["--no-sandbox"] + } + }, + + // Continuous Integration mode + // if true, Karma captures browsers, runs the tests and exits + singleRun: false, + + // Concurrency level + // how many browser should be started simultaneous + concurrency: 1, + + browserNoActivityTimeout: 600000, + browserDisconnectTimeout: 10000, + browserDisconnectTolerance: 3, + + client: { + mocha: { + // change Karma's debug.html to the mocha web reporter + reporter: "html", + timeout: "600000" + } + } + }); +}; diff --git a/sdk/appconfiguration/app-configuration/package.json b/sdk/appconfiguration/app-configuration/package.json index a8ce93a867ab..079a7a4e68cb 100644 --- a/sdk/appconfiguration/app-configuration/package.json +++ b/sdk/appconfiguration/app-configuration/package.json @@ -2,7 +2,7 @@ "name": "@azure/app-configuration", "author": "Microsoft Corporation", "description": "An isomorphic client library for the Azure App Configuration service.", - "version": "1.0.2", + "version": "1.1.0", "sdk-type": "client", "keywords": [ "node", @@ -23,6 +23,9 @@ "bugs": { "url": "https://github.com/Azure/azure-sdk-for-js/issues" }, + "browser": { + "./dist-esm/src/internal/cryptoHelpers.js": "./dist-esm/src/internal/cryptoHelpers.browser.js" + }, "files": [ "dist/**/*.js", "dist/**/*.js.map", @@ -38,12 +41,16 @@ ], "scripts": { "audit": "node ../../../common/scripts/rush-audit.js && rimraf node_modules package-lock.json && npm i --package-lock-only 2>&1 && npm audit", - "build": "tsc -p . && rollup -c 2>&1 && npm run extract-api", - "build:test": "tsc -p . && rollup -c rollup.test.config.js 2>&1", + "build": "npm run build:node && npm run build:browser", + "build:node": "tsc -p . && cross-env ONLY_NODE=true rollup -c 2>&1 && npm run extract-api", + "build:browser": "tsc -p . && cross-env ONLY_BROWSER=true rollup -c 2>&1", + "build:test": "npm run build:test:node && npm run build:test:browser", + "build:test:node": "tsc -p . && cross-env ONLY_NODE=true rollup -c rollup.test.config.js 2>&1", + "build:test:browser": "tsc -p . && cross-env ONLY_BROWSER=true rollup -c rollup.test.config.js 2>&1", "build:samples": "node ../../../common/scripts/prep-samples.js && cd samples && tsc", "check-format": "prettier --list-different --config ../../.prettierrc.json --ignore-path ../../.prettierignore \"src/**/*.ts\" \"test/**/*.ts\" \"*.{js,json}\"", - "clean": "rimraf dist dist-esm dist-test types *.tgz *.log", - "coverage": "nyc --reporter=lcov --exclude-after-remap=false mocha -t 120000 dist-test/index.js --reporter ../../../common/tools/mocha-multi-reporter.js", + "clean": "rimraf dist dist-esm dist-browser test-dist test-browser types *.tgz *.log", + "coverage": "nyc --reporter=lcov --exclude-after-remap=false mocha -t 120000 test-dist/index.js --reporter ../../../common/tools/mocha-multi-reporter.js", "execute:samples": "npm run build:samples && echo Skipped.", "extract-api": "tsc -p . && api-extractor run --local", "format": "prettier --write --config ../../.prettierrc.json --ignore-path ../../.prettierignore \"src/**/*.ts\" \"test/**/*.ts\" \"*.{js,json}\"", @@ -52,14 +59,14 @@ "prebuild": "npm run clean", "pack": "npm pack 2>&1", "swagger": "autorest --typescript swagger/swagger.md", - "integration-test:browser": "echo skipped", - "integration-test:node": "nyc mocha -r esm --require source-map-support/register --reporter ../../../common/tools/mocha-multi-reporter.js --timeout 180000 --full-trace dist-esm/test/*.spec.js dist-esm/test/**/*.spec.js", - "integration-test": "npm run unit-test:node && npm run unit-test:browser", - "test:browser": "npm run clean && npm run build:test && npm run unit-test:browser", - "test:node": "npm run clean && npm run build:test && npm run unit-test:node", + "integration-test": "npm run integration-test:node && npm run integration-test:browser", + "integration-test:browser": "npm run build:test:browser && cross-env TEST_MODE=live karma start --single-run", + "integration-test:node": "npm run build:test:node && nyc mocha -r esm --require source-map-support/register --reporter ../../../common/tools/mocha-multi-reporter.js --timeout 180000 --full-trace dist-esm/test/*.spec.js dist-esm/test/**/*.spec.js", + "test:browser": "npm run clean && npm run build:test:browser && npm run unit-test:browser", + "test:node": "npm run clean && npm run build:test:node && npm run unit-test:node", "test": "npm run clean && npm run build:test && npm run unit-test", - "unit-test:browser": "echo skipped", - "unit-test:node": "mocha --require source-map-support/register --reporter ../../../common/tools/mocha-multi-reporter.js --timeout 180000 --full-trace dist-test/index.node.js", + "unit-test:browser": "", + "unit-test:node": "mocha --require source-map-support/register --reporter ../../../common/tools/mocha-multi-reporter.js --timeout 180000 --full-trace test-dist/index.node.js", "unit-test": "npm run unit-test:node && npm run unit-test:browser" }, "sideEffects": false, @@ -85,6 +92,8 @@ "@azure/test-utils-recorder": "^1.0.0", "@microsoft/api-extractor": "7.7.11", "@rollup/plugin-commonjs": "11.0.2", + "@rollup/plugin-inject": "^4.0.0", + "@rollup/plugin-json": "^4.0.0", "@rollup/plugin-multi-entry": "^3.0.0", "@rollup/plugin-node-resolve": "^8.0.0", "@rollup/plugin-replace": "^2.2.0", @@ -101,6 +110,17 @@ "eslint-plugin-no-only-tests": "^2.3.0", "eslint-plugin-promise": "^4.1.1", "esm": "^3.2.18", + "karma": "^4.0.1", + "karma-chrome-launcher": "^3.0.0", + "karma-coverage": "^2.0.0", + "karma-edge-launcher": "^0.4.2", + "karma-env-preprocessor": "^0.1.1", + "karma-firefox-launcher": "^1.1.0", + "karma-ie-launcher": "^1.0.0", + "karma-junit-reporter": "^2.0.1", + "karma-mocha": "^1.3.0", + "karma-mocha-reporter": "^2.2.5", + "karma-remap-istanbul": "^0.6.0", "mocha": "^7.1.1", "mocha-junit-reporter": "^1.18.0", "nock": "^12.0.3", @@ -108,12 +128,13 @@ "prettier": "^1.16.4", "rimraf": "^3.0.0", "rollup": "^1.16.3", + "rollup-plugin-shim": "^1.0.0", "rollup-plugin-sourcemaps": "^0.4.2", "rollup-plugin-terser": "^5.1.1", "sinon": "^9.0.2", "ts-node": "^8.3.0", "typescript": "~3.9.3", "uglify-js": "^3.4.9", - "@rollup/plugin-json": "^4.0.0" + "cross-env": "^7.0.2" } } diff --git a/sdk/appconfiguration/app-configuration/rollup.base.config.js b/sdk/appconfiguration/app-configuration/rollup.base.config.js index c7a5ebf75508..38f0910b7b52 100644 --- a/sdk/appconfiguration/app-configuration/rollup.base.config.js +++ b/sdk/appconfiguration/app-configuration/rollup.base.config.js @@ -6,6 +6,8 @@ import { terser } from "rollup-plugin-terser"; import sourcemaps from "rollup-plugin-sourcemaps"; import shim from "rollup-plugin-shim"; import json from "@rollup/plugin-json"; +import * as path from "path"; +import inject from "@rollup/plugin-inject"; const pkg = require("./package.json"); const depNames = Object.keys(pkg.dependencies); @@ -23,8 +25,27 @@ const banner = [ " */" ].join("\n"); +const ignoreKnownWarnings = (warning) => { + if (warning.code === "THIS_IS_UNDEFINED") { + // This error happens frequently due to TypeScript emitting `this` at the + // top-level of a module. In this case its fine if it gets rewritten to + // undefined, so ignore this error. + return; + } + + if ( + warning.code === "CIRCULAR_DEPENDENCY" && + warning.importer.indexOf(path.normalize("node_modules/chai/lib") === 0) + ) { + // Chai contains circular references, but they are not fatal and can be ignored. + return; + } + + console.error(`(!) ${warning.message}`); +}; + export function nodeConfig(test = false) { - const externalNodeBuiltins = ["events"]; + const externalNodeBuiltins = ["events", "crypto", "path"]; const baseConfig = { input: input, external: depNames.concat(externalNodeBuiltins), @@ -39,10 +60,7 @@ export function nodeConfig(test = false) { plugins: [ sourcemaps(), replace({ - delimiters: ["", ""], - // replace dynamic checks with if (true) since this is for node only. - // Allows rollup's dead code elimination to be more aggressive. - "if (isNode)": "if (true)" + delimiters: ["", ""] }), nodeResolve({ preferBuiltins: true }), cjs() @@ -58,7 +76,7 @@ export function nodeConfig(test = false) { ); // different output file - baseConfig.output.file = "dist-test/index.node.js"; + baseConfig.output.file = "test-dist/index.node.js"; // mark assert packages we use as external baseConfig.external.push("assert"); @@ -75,3 +93,79 @@ export function nodeConfig(test = false) { return baseConfig; } + +export function browserConfig(test = false) { + const baseConfig = { + input: input, + output: { + file: "dist-browser/appconfiguration.js", + format: "umd", + name: "Azure.AppConfiguration", + globals: { + "@azure/core-http": "Azure.Core.HTTP" + }, + sourcemap: true + }, + external: ["nock", "fs-extra"], + preserveSymlinks: false, + plugins: [ + sourcemaps(), + replace({ + delimiters: ["", ""] + }), + + nodeResolve({ + mainFields: ["module", "browser"], + preferBuiltins: false + }), + cjs({ + namedExports: { + chai: ["assert", "expect", "use"], + assert: ["ok", "equal", "strictEqual", "deepEqual", "fail", "throws", "notEqual"], + events: ["EventEmitter"], + "@opentelemetry/api": ["CanonicalCode", "SpanKind", "TraceFlags"] + } + }), + + inject({ + modules: { + process: "process" + }, + exclude: ["./**/package.json"] + }), + + json() + ] + }; + + baseConfig.onwarn = ignoreKnownWarnings; + + if (test) { + baseConfig.input = ["dist-esm/test/*.spec.js", "dist-esm/test/internal/*.spec.js"]; + + baseConfig.external.unshift(...["process"]); + + baseConfig.output.globals = { + ...baseConfig.output.globals, + nock: "nock", + fs: "fs-extra", + "fs-extra": "fs", + process: "process", + path: "path" + }; + + baseConfig.plugins.unshift(multiEntry({ exports: false })); + baseConfig.plugins.unshift( + ...[shim({ path: `export function join() {}`, dotenv: `export function config() { }` })] + ); + + baseConfig.output.file = "test-browser/index.js"; + + // Disable tree-shaking of test code. In rollup-plugin-node-resolve@5.0.0, rollup started respecting + // the "sideEffects" field in package.json. Since our package.json sets "sideEffects=false", this also + // applies to test code, which causes all tests to be removed by tree-shaking. + baseConfig.treeshake = false; + } + + return baseConfig; +} diff --git a/sdk/appconfiguration/app-configuration/rollup.config.js b/sdk/appconfiguration/app-configuration/rollup.config.js index de6b48740722..14652aa67ed8 100644 --- a/sdk/appconfiguration/app-configuration/rollup.config.js +++ b/sdk/appconfiguration/app-configuration/rollup.config.js @@ -2,6 +2,12 @@ import * as base from "./rollup.base.config"; const inputs = []; -inputs.push(base.nodeConfig()); +if (!process.env.ONLY_BROWSER) { + inputs.push(base.nodeConfig()); +} + +if (!process.env.ONLY_NODE) { + inputs.push(base.browserConfig()); +} export default inputs; diff --git a/sdk/appconfiguration/app-configuration/rollup.test.config.js b/sdk/appconfiguration/app-configuration/rollup.test.config.js index c6723abed962..48ea762bf9e0 100644 --- a/sdk/appconfiguration/app-configuration/rollup.test.config.js +++ b/sdk/appconfiguration/app-configuration/rollup.test.config.js @@ -1,3 +1,16 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + import * as base from "./rollup.base.config"; -export default [base.nodeConfig(true)]; +const inputs = []; + +if (!process.env.ONLY_BROWSER) { + inputs.push(base.nodeConfig({ test: true })); +} + +if (!process.env.ONLY_NODE) { + inputs.push(base.browserConfig({ test: true })); +} + +export default inputs; diff --git a/sdk/appconfiguration/app-configuration/src/appConfigCredential.ts b/sdk/appconfiguration/app-configuration/src/appConfigCredential.ts index 5b5cc7c80613..78042d3217ca 100644 --- a/sdk/appconfiguration/app-configuration/src/appConfigCredential.ts +++ b/sdk/appconfiguration/app-configuration/src/appConfigCredential.ts @@ -1,8 +1,8 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT license. -import { createHash, createHmac } from "crypto"; import { ServiceClientCredentials, WebResource, URLBuilder } from "@azure/core-http"; +import { sha256Digest, sha256Hmac } from "./internal/cryptoHelpers"; /** * @internal @@ -23,12 +23,11 @@ export class AppConfigCredential implements ServiceClientCredentials { * @param {WebResource} webResource The WebResource to be signed. * @returns {Promise} The signed request object. */ - signRequest(webResource: WebResource): Promise { + async signRequest(webResource: WebResource): Promise { const verb = webResource.method.toUpperCase(); const utcNow = new Date().toUTCString(); - const contentHash = createHash("sha256") - .update(webResource.body || "") - .digest("base64"); + + const contentHash = await sha256Digest(webResource.body || ""); const signedHeaders = "x-ms-date;host;x-ms-content-sha256"; @@ -38,10 +37,7 @@ export class AppConfigCredential implements ServiceClientCredentials { const stringToSign = `${verb}\n${urlPathAndQuery}\n${utcNow};${url.getHost()};${contentHash}`; - const decodedSecret = Buffer.from(this.secret, "base64"); - var signature = createHmac("sha256", decodedSecret) - .update(stringToSign) - .digest("base64"); + const signature = await sha256Hmac(this.secret, stringToSign); webResource.headers.set("x-ms-date", utcNow); webResource.headers.set("x-ms-content-sha256", contentHash); @@ -50,6 +46,6 @@ export class AppConfigCredential implements ServiceClientCredentials { `HMAC-SHA256 Credential=${this.credential}, SignedHeaders=${signedHeaders}, Signature=${signature}` ); - return Promise.resolve(webResource); + return webResource; } } diff --git a/sdk/appconfiguration/app-configuration/src/appConfigurationClient.ts b/sdk/appconfiguration/app-configuration/src/appConfigurationClient.ts index ba1807ce3112..0c8c71b3d778 100644 --- a/sdk/appconfiguration/app-configuration/src/appConfigurationClient.ts +++ b/sdk/appconfiguration/app-configuration/src/appConfigurationClient.ts @@ -67,7 +67,7 @@ const packageName = "azsdk-js-app-configuration"; * @internal * @ignore */ -export const packageVersion = "1.0.2"; +export const packageVersion = "1.1.0"; const apiVersion = "1.0"; const ConnectionStringRegex = /Endpoint=(.*);Id=(.*);Secret=(.*)/; const deserializationContentTypes = { @@ -109,11 +109,6 @@ export interface InternalAppConfigurationClientOptions extends AppConfigurationC * NOTE: this is an internal option, not for general client usage. */ syncTokens?: SyncTokens; - /** - * Whether we want to run as if we're in node or in the browser. - * (currently only affects which name we use for the user agent header) - */ - isNodeOverride?: boolean; } /** @@ -543,7 +538,7 @@ export function getGeneratedClientOptions( ...defaults ], generateClientRequestIdHeader: true, - userAgentHeaderName: getUserAgentHeaderName(internalAppConfigOptions.isNodeOverride), + userAgentHeaderName: getUserAgentHeaderName(), userAgent }; } @@ -566,10 +561,8 @@ export function getUserAgentPrefix(userSuppliedUserAgent: string | undefined): s * @ignore * @internal */ -function getUserAgentHeaderName(isNodeOverride: boolean | undefined): string { - const definitelyIsNode = isNodeOverride != null ? isNodeOverride : coreHttpIsNode; - - if (definitelyIsNode) { +function getUserAgentHeaderName(): string { + if (coreHttpIsNode) { return "User-Agent"; } else { // we only need to override this when we're in the browser diff --git a/sdk/appconfiguration/app-configuration/src/internal/cryptoHelpers.browser.ts b/sdk/appconfiguration/app-configuration/src/internal/cryptoHelpers.browser.ts new file mode 100644 index 000000000000..b62321bc88a4 --- /dev/null +++ b/sdk/appconfiguration/app-configuration/src/internal/cryptoHelpers.browser.ts @@ -0,0 +1,41 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +/// + +/** + * @internal + * @ignore + */ +export async function sha256Digest(body: string | undefined): Promise { + const digest = await self.crypto.subtle.digest("SHA-256", new TextEncoder().encode(body || "")); + + // The conversions here are a bit odd but necessary (see "Unicode strings" in the link below) + // https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/btoa + return btoa(String.fromCharCode(...new Uint8Array(digest))); +} + +/** + * @internal + * @ignore + */ +export async function sha256Hmac(secret: string, stringToSign: string): Promise { + const key = await self.crypto.subtle.importKey( + "raw", + Uint8Array.from(atob(secret), (c) => c.charCodeAt(0)), + { + name: "HMAC", + hash: "SHA-256" + }, + false, + ["sign"] + ); + + const sigArray = await self.crypto.subtle.sign( + "HMAC", + key, + new TextEncoder().encode(stringToSign) + ); + + return btoa(String.fromCharCode(...new Uint8Array(sigArray))); +} diff --git a/sdk/appconfiguration/app-configuration/src/internal/cryptoHelpers.ts b/sdk/appconfiguration/app-configuration/src/internal/cryptoHelpers.ts new file mode 100644 index 000000000000..ff57a4d48172 --- /dev/null +++ b/sdk/appconfiguration/app-configuration/src/internal/cryptoHelpers.ts @@ -0,0 +1,26 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT license. + +import { createHash, createHmac } from "crypto"; + +/** + * @internal + * @ignore + */ +export async function sha256Digest(body: string | undefined): Promise { + return createHash("sha256") + .update(body || "") + .digest("base64"); +} + +/** + * @internal + * @ignore + */ +export async function sha256Hmac(secret: string, stringToSign: string): Promise { + const decodedSecret = Buffer.from(secret, "base64"); + + return createHmac("sha256", decodedSecret) + .update(stringToSign) + .digest("base64"); +} diff --git a/sdk/appconfiguration/app-configuration/src/internal/helpers.ts b/sdk/appconfiguration/app-configuration/src/internal/helpers.ts index be1d0b7bbd55..7c0db6410985 100644 --- a/sdk/appconfiguration/app-configuration/src/internal/helpers.ts +++ b/sdk/appconfiguration/app-configuration/src/internal/helpers.ts @@ -3,7 +3,6 @@ import { ListConfigurationSettingsOptions } from ".."; import { URLBuilder } from "@azure/core-http"; -import { isArray } from "util"; import { ListRevisionsOptions, ConfigurationSettingId, @@ -129,7 +128,7 @@ export function extractAfterTokenFromNextLink(nextLink: string) { let parsedLink = URLBuilder.parse(nextLink); let afterToken = parsedLink.getQueryParameterValue("after"); - if (afterToken == null || isArray(afterToken)) { + if (afterToken == null || Array.isArray(afterToken)) { throw new Error("Invalid nextLink - invalid after token"); } diff --git a/sdk/appconfiguration/app-configuration/test/index.spec.ts b/sdk/appconfiguration/app-configuration/test/index.spec.ts index 48dea835b1df..83b99bcf3267 100644 --- a/sdk/appconfiguration/app-configuration/test/index.spec.ts +++ b/sdk/appconfiguration/app-configuration/test/index.spec.ts @@ -659,7 +659,7 @@ describe("AppConfigurationClient", () => { // this number is arbitrarily chosen to match the size of a page + 1 const expectedNumberOfLabels = 200; - const addSettingPromises = []; + let addSettingPromises = []; for (let i = 0; i < expectedNumberOfLabels; i++) { addSettingPromises.push( @@ -669,6 +669,11 @@ describe("AppConfigurationClient", () => { label: i.toString() }) ); + + if (i !== 0 && i % 10 === 0) { + await Promise.all(addSettingPromises); + addSettingPromises = []; + } } await Promise.all(addSettingPromises); diff --git a/sdk/appconfiguration/app-configuration/test/internal/http.spec.ts b/sdk/appconfiguration/app-configuration/test/internal/http.spec.ts index aca0e0265b94..b870d53b7208 100644 --- a/sdk/appconfiguration/app-configuration/test/internal/http.spec.ts +++ b/sdk/appconfiguration/app-configuration/test/internal/http.spec.ts @@ -13,6 +13,7 @@ import { } from "../testHelpers"; import * as chai from "chai"; import { Recorder } from "@azure/test-utils-recorder"; +import { isNode } from "@azure/core-http"; describe("http request related tests", function() { describe("unit tests", () => { @@ -35,27 +36,17 @@ describe("http request related tests", function() { }); it("useragentheadername", () => { - let options = getGeneratedClientOptions("base-uri", new SyncTokens(), { - isNodeOverride: false - }); - - assert.equal( - options.userAgentHeaderName, - "x-ms-useragent", - "Pretending we're running in a browser." - ); - - options = getGeneratedClientOptions("base-uri", new SyncTokens(), { - isNodeOverride: true - }); + let expectedUserHeaderName; - assert.equal(options.userAgentHeaderName, "User-Agent", "Pretending we're running in node."); + if (isNode) { + expectedUserHeaderName = "User-Agent"; + } else { + expectedUserHeaderName = "x-ms-useragent"; + } - // since we're only running these tests in node this will be the same as the - // case above (undefined, thus using the normal User-Agent header) - options = getGeneratedClientOptions("base-uri", new SyncTokens(), {}); + let options = getGeneratedClientOptions("base-uri", new SyncTokens(), {}); - assert.equal(options.userAgentHeaderName, "User-Agent", "We know that we're running node."); + assert.equal(options.userAgentHeaderName, expectedUserHeaderName); }); it("useragent", () => { @@ -161,6 +152,11 @@ describe("http request related tests", function() { let scope: nock.Scope; beforeEach(function() { + if (nock == null || nock.recorder == null) { + this.skip(); + return; + } + syncTokens = new SyncTokens(); client = @@ -178,6 +174,10 @@ describe("http request related tests", function() { }); afterEach(function() { + if (nock == null || nock.recorder == null) { + return; + } + if (!this.currentTest?.isPending()) { assert.ok(scope.isDone()); } diff --git a/sdk/appconfiguration/app-configuration/test/package.spec.ts b/sdk/appconfiguration/app-configuration/test/package.spec.ts index 14f5891c68d1..bdcfba4b28fb 100644 --- a/sdk/appconfiguration/app-configuration/test/package.spec.ts +++ b/sdk/appconfiguration/app-configuration/test/package.spec.ts @@ -1,12 +1,17 @@ import { join } from "path"; import * as assert from "assert"; +import { isNode } from "@azure/core-http"; import { packageVersion } from "../src/appConfigurationClient"; describe("packagejson related tests", () => { // if this test is failing you need to update the contant `packageVersion` referenced above // in the generated code. - it("user agent string matches the package version", () => { + it("user agent string matches the package version", function() { + if (!isNode) { + this.skip(); + } + let packageJsonContents: { [property: string]: string; }; diff --git a/sdk/appconfiguration/app-configuration/tests.yml b/sdk/appconfiguration/app-configuration/tests.yml index 05592d751807..2f1e6d7fe2af 100644 --- a/sdk/appconfiguration/app-configuration/tests.yml +++ b/sdk/appconfiguration/app-configuration/tests.yml @@ -5,7 +5,7 @@ extends: parameters: PackageName: "@azure/app-configuration" ResourceServiceDirectory: appconfiguration - TestBrowser: false + TestBrowser: true TestSamples: false EnvVars: AZURE_CLIENT_ID: $(aad-azure-sdk-test-client-id)