diff --git a/.eslintrc.js b/.eslintrc.js new file mode 100644 index 00000000000..8cdd5c498c1 --- /dev/null +++ b/.eslintrc.js @@ -0,0 +1,43 @@ +module.exports = { + "env": { + "browser": true, + "commonjs": true + }, + "extends": "standard", + "globals": { + "$$PREBID_GLOBAL$$": false + }, + "parserOptions": { + "sourceType": "module" + }, + "rules": { + "comma-dangle": "off", + "semi": "off", + "space-before-function-paren": "off", + + // Exceptions below this line are temporary, so that eslint can be added into the CI process. + // Violations of these styles should be fixed, and the exceptions removed over time. + // + // See Issue #1111. + "brace-style": "off", + "camelcase": "off", + "eqeqeq": "off", + "import/first": "off", + "new-cap": "off", + "no-control-regex": "off", + "no-mixed-operators": "off", + "no-multiple-empty-lines": "off", + "no-redeclare": "off", + "no-return-assign": "off", + "no-throw-literal": "off", + "no-undef": "off", + "no-unused-vars": "off", + "no-use-before-define": "off", + "no-useless-call": "off", + "no-useless-escape": "off", + "one-var": "off", + "standard/no-callback-literal": "off", + "standard/object-curly-even-spacing": "off", + "valid-typeof": "off" + } +}; diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 1dc04a9c2b7..61eb327fd2c 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -26,6 +26,9 @@ Thank you for your pull request. Please make sure this PR is scoped to one chang } } ``` + +Be sure to test the integration with your adserver using the [Hello World](/integrationExamples/gpt/hello_world.html) sample page. + - contact email of the adapter’s maintainer - [ ] official adapter submission diff --git a/.gitignore b/.gitignore index 88e849a35ad..eb05c8d024b 100644 --- a/.gitignore +++ b/.gitignore @@ -26,6 +26,7 @@ build/coverage/ ## Directory-based project format: .idea/ +.vscode/ # if you remove the above rule, at least ignore the following: # User-specific stuff: diff --git a/.jscsrc b/.jscsrc deleted file mode 100644 index a74740263ff..00000000000 --- a/.jscsrc +++ /dev/null @@ -1,11 +0,0 @@ -{ - "maxErrors": 1000, - "requireTrailingComma": null, - "requireCamelCaseOrUpperCaseIdentifiers": null, - "requireSpacesInAnonymousFunctionExpression": null, - "validateIndentation": 2, - "disallowSpacesInFunctionDeclaration": { - "beforeOpeningRoundBrace": true - }, - "disallowNewlineBeforeBlockStatements": true -} diff --git a/.jshintrc b/.jshintrc deleted file mode 100644 index a51c32f4328..00000000000 --- a/.jshintrc +++ /dev/null @@ -1,39 +0,0 @@ -{ - "bitwise": false, - "browser": true, - "curly": false, - "devel": true, - "eqeqeq": true, - "freeze": true, - "immed": true, - "maxdepth": 5, - "newcap": true, - "noarg": true, - "node": true, - "notypeof": true, - "esnext": true, - "trailing": true, - "undef": true, - "unused": true, - "strict": false, - "scripturl": true, - "globals": { - "before": true, - "after": true, - "exports": true, - "$$PREBID_GLOBAL$$": true, - "pbjsTestOnly": true, - "assert": false, - "expect": false, - "dump": false, - "describe": false, - "it": false, - "xit": false, - "pkg": false, - "sinon": false, - "beforeEach": false, - "afterEach": false, - "JSON": true, - "Criteo": true - } -} diff --git a/.nvmrc b/.nvmrc index a75b92f1ed7..4fedf1d20e1 100644 --- a/.nvmrc +++ b/.nvmrc @@ -1 +1 @@ -5.1 +7.0 diff --git a/.travis.yml b/.travis.yml index 8addbe93b94..73b5de5ae4a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,23 +1,17 @@ -sudo: required dist: trusty language: node_js node_js: - - "5.1" + - "7.0" +# See https://docs.travis-ci.com/user/gui-and-headless-browsers/#Using-the-Chrome-addon-in-the-headless-mode addons: - apt: - sources: - - google-chrome - packages: - - google-chrome-stable + chrome: stable before_install: - npm install -g gulp - - export CHROME_BIN=google-chrome - - export DISPLAY=:99.0 - - sh -e /etc/init.d/xvfb start + - google-chrome-stable --headless --disable-gpu --remote-debugging-port=9222 http://localhost & script: - gulp run-tests diff --git a/CHANGELOG b/CHANGELOG index ef979910b96..abcb0a49d6a 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,24 @@ +AOL Prebid 1.25.0 +---------------- +Updated to Prebid 0.26.1 + + +AOL Prebid 1.24.0 +---------------- +Updated to Prebid 0.25.0 + + +AOL Prebid 1.23.0 +---------------- +Added passing key values feature. +Updated to Prebid 0.24.1 + + +AOL Prebid 1.22.0 +---------------- +Added aliases for AOL adapter. + + AOL Prebid 1.21.0 ---------------- Updated to Prebid 0.23.1 diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index b2895cd8982..5856835f785 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,24 +1,42 @@ # Contributing to Prebid.js -Contributions are always welcome. To contribute, [fork](https://help.github.com/articles/fork-a-repo/) Prebid.js, commit your changes, and [open a pull request](https://help.github.com/articles/using-pull-requests/). +Contributions are always welcome. To contribute, [fork](https://help.github.com/articles/fork-a-repo/) Prebid.js, +commit your changes, and [open a pull request](https://help.github.com/articles/using-pull-requests/) against the +master branch. -## Pull Requests -Please make sure that pull requests are scoped to one change, and that any added or changed code includes tests with greater than 80% code coverage. See [Testing Prebid.js](#testing-prebidjs) for help on writing tests. +Pull requests must have 80% code coverage before beign considered for merge. +Additional details about the process can be found [here](./pr_review.md). ## Issues -[prebid.org](http://prebid.org/) contains documentation that may help answer questions you have about using Prebid.js. If you can't find the answer there, try searching for a similar issue on the [issues page](https://github.com/prebid/Prebid.js/issues). If you don't find an answer there, [open a new issue](https://github.com/prebid/Prebid.js/issues/new). +[prebid.org](http://prebid.org/) contains documentation that may help answer questions you have about using Prebid.js. +If you can't find the answer there, try searching for a similar issue on the [issues page](https://github.com/prebid/Prebid.js/issues). +If you don't find an answer there, [open a new issue](https://github.com/prebid/Prebid.js/issues/new). ## Documentation If you have a documentation issue or pull request, please open a ticket or PR in the [documentation repository](https://github.com/prebid/prebid.github.io). -## Testing Prebid.js -Pull requests to the Prebid.js library will need to include tests with greater than 80% code coverage for any changed/added code before they can be merged into master. +## Writing Tests -This section describes how to test code in the Prebid.js repository to help prepare your pull request. +Prebid uses [Mocha](http://mochajs.org/) and [Chai](http://chaijs.com/) for unit tests. [Sinon](http://sinonjs.org/) +provides mocks, stubs, and spies. [Karma](https://karma-runner.github.io/1.0/index.html) runs the tests and generates +code coverage reports at `build/coverage/lcov/lcov-report/index.html`. -### Writing tests +Tests are stored in the [test/spec](test/spec) directory. Tests for Adapters are located in [test/spec/adapters](test/spec/adapters). +They can be run with the following commands: + +- `gulp test` - run the test suite once (`npm test` is aliased to call `gulp test`) +- `gulp serve` - run the test suite once, but re-run it whenever a file in the `src` or `test` directory is modified + +Before a Pull Request will be considered for merge: + +- All new and existing tests must pass +- Added or modified code must have greater than 80% coverage + +If you are submitting an adapter, you can also use the [Hello World](integrationExamples/gpt/hello_world.html) example page to test integration with your server. + +### Test Guidelines When you are adding code to Prebid.js, or modifying code that isn't covered by an existing test, test the code according to these guidelines: -- If the module you are working on is already partially tested by a file within the `test` directory, add tests to that file +- If the module you are working on is already partially tested by a file within the `test/spec` directory, add tests to that file - If the module does not have any tests, create a new test file - Group tests in a `describe` block - Test individual units of code within an `it` block @@ -36,31 +54,8 @@ When you are adding code to Prebid.js, or modifying code that isn't covered by a - If you need to check `adloader.loadScript` in a test, use a `stub` rather than a `spy`. `spy`s trigger a network call which can result in a `script error` and cause unrelated unit tests to fail. `stub`s will let you gather information about the `adloader.loadScript` call without affecting external resources - When writing tests you may use ES2015 syntax if desired -### Running tests -After checking out the Prebid.js repository and installing dev dependencies with `npm install`, use the following commands to run tests as you are working on code: - -- `gulp test` will run the test suite once (`npm test` is aliased to call `gulp test`) -- `gulp serve` will run tests once and stay open, re-running tests whenever a file in the `src` or `test` directory is modified - -### Checking results and code coverage -Check the test results using these guidelines: - -- Look at the total number of tests run, passed, and failed in the shell window. -- If all tests are passing, great. -- Otherwise look for errors printed in the console for a description of the failing test. -- You may need to iterate on your code or tests until all tests are passing. -- Make sure existing tests still pass. -- There is a table below the testing report that shows code coverage percentage, for each file under the `src` directory. -- Each time you run tests, a code coverage report is generated in `build/coverage/lcov/lcov-report/index.html`. -- This is a static HTML page that you can load in your browser. -- On that page, navigate to the file you are testing to see which lines are being tested. -- Red indicates that a line isn't covered by a test. -- Gray indicates a line that doesn't need coverage, such as a comment or blank line. -- Green indicates a line that is covered by tests. -- The code you have added or modified must have greater than 80% coverage to be accepted. - -### Examples -Prebid.js already has lots of tests. Read them to see how Prebid.js is tested, and for inspiration: +### Test Examples +Prebid.js already has many tests. Read them to see how Prebid.js is tested, and for inspiration: - Look in `test/spec` and its subdirectories - Tests for bidder adaptors are located in `test/spec/adapters` @@ -82,10 +77,3 @@ describe('', () => { // Add other `describe` or `it` blocks as necessary }); ``` - -### Resources -The Prebid.js testing stack contains some of the following tools. It may be helpful to consult their documentation during the testing process. - -- [Mocha - test framework](http://mochajs.org/) -- [Chai - BDD/TDD assertion library](http://chaijs.com/) -- [Sinon - spy, stub, and mock library](http://sinonjs.org/) diff --git a/README.md b/README.md index 987372d29d9..c226e8027a4 100644 --- a/README.md +++ b/README.md @@ -42,7 +42,9 @@ This URL is designed specifically for the Container Tag library and it supports > A free and open source library for publishers to quickly implement header bidding. -This README is for developers who want to contribute to Prebid.js. For user-facing documentation, see [Prebid.org](http://prebid.org). +This README is for developers who want to contribute to Prebid.js. +Additional documentation can be found at [the Prebid homepage](http://prebid.org). +Working examples can be found in [the developer docs](http://prebid.org/dev-docs/getting-started.html). **Table of Contents** @@ -59,13 +61,15 @@ This README is for developers who want to contribute to Prebid.js. For user-fac $ cd Prebid.js $ yarn install -Prebid now supports the `yarn` npm client. This is an alternative to using `npm` for package management, though `npm` will continue to work as before. +Prebid supports the `yarn` npm client. This is an alternative to using `npm` for package management, though `npm install` will continue to work as before. -For more info about yarn see https://yarnpkg.com +For more info, see [the Yarn documentation](https://yarnpkg.com). + +*Note:* You need to have `NodeJS` 4.x or greater installed. -## Build for Dev +## Build for Development To build the project on your local machine, run: @@ -78,21 +82,13 @@ This runs some code quality checks, starts a web server at `http://localhost:999 + `./build/dist/prebid.js` - Minified production code + `./prebid.js_.zip` - Distributable zip archive -*Note:* You need to have `node.js` 4.x or greater installed to be able to run the `gulp build` commands. - ### Build Optimization -The standard build output contains all the available bidder adapters listed in `adapters.json`. - -You might want to exclude some/most of them from the final bundle. To make sure the build only includes the adapters you want, you can make your own adapters file. +The standard build output contains all the available modules from within the `modules` folder. -For example, in `path/to/your/list-of-adapters.json`, write: +You might want to exclude some/most of them from the final bundle. To make sure the build only includes the modules you want, you can specify the modules to be included with the `--modules` CLI argument. - [ - "openx", - "rubicon", - "sovrn" - ] +For example, when running the serve command: `gulp serve --modules=openxBidAdapter,rubiconBidAdapter,sovrnBidAdapter` Building with just these adapters will result in a smaller bundle which should allow your pages to load faster. @@ -102,26 +98,35 @@ Prebid now supports the `yarn` npm client. This is an alternative to using `npm` For more info about yarn see https://yarnpkg.com - Clone the repo, run `yarn install` -- Duplicate `adapters.json` to e.g. `list-of-adapters.json` -- Remove the unnecessary adapters from `list-of-adapters.json` - Then run the build: - $ gulp build --adapters path/to/your/list-of-adapters.json + $ gulp build --modules=openxBidAdapter,rubiconBidAdapter,sovrnBidAdapter + +Alternatively, a `.json` file can be specified that contains a list of modules you would like to include. + + $ gulp build --modules=modules.json + +With `modules.json` containing the following +```json modules.json +[ + "openxBidAdapter", + "rubiconBidAdapter", + "sovrnBidAdapter" +] +``` **Build prebid.js using Yarn for bundling** In case you'd like to explicitly show that your project uses `prebid.js` and want a reproducible build, consider adding it as an `yarn` dependency. - Add `prebid.js` as a `yarn` dependency of your project: `yarn add prebid.js` -- Duplicate `node_modules/prebid.js/adapters.json` to under your project path, e.g. `path/to/your/list-of-adapters.json` -- Remove the unnecessary adapters - Run the `prebid.js` build under the `node_modules/prebid.js/` folder - $ gulp build --adapters path/to/your/list-of-adapters.json + $ gulp build --modules=path/to/your/list-of-modules.json Most likely your custom `prebid.js` will only change when there's: -- A change in your list of adapters +- A change in your list of modules - A new release of `prebid.js` Having said that, you are probably safe to check your custom bundle into your project. You can also generate it in your build process. @@ -130,7 +135,26 @@ Having said that, you are probably safe to check your custom bundle into your pr ## Test locally -To configure Prebid.js to run locally, edit the example file `./integrationExamples/gpt/pbjs_example_gpt.html`: +To lint the code: + +```bash +gulp lint +``` + +To run the unit tests: + +```bash +gulp test +``` + +To generate and view the code coverage reports: + +```bash +gulp test-coverage +gulp view-coverage +``` + +For end-to-end testing, edit the example file `./integrationExamples/gpt/pbjs_example_gpt.html`: 1. Change `{id}` values appropriately to set up ad units and bidders 2. Set the path to Prebid.js in your example file as shown below (see `pbs.src`). @@ -159,21 +183,21 @@ For deployment: })(); ``` -To run the project locally, use: +Build and run the project locally with: - $ gulp serve +```bash +gulp serve +``` -This runs code quality checks, generates all the necessary files and starts a web server at `http://localhost:9999` serving from the project root. Navigate to your example implementation to test, and if your `prebid.js` file is sourced from the `./build/dev` directory you will have sourcemaps available in your browser's developer tools. +This runs `lint` and `test`, then starts a web server at `http://localhost:9999` serving from the project root. +Navigate to your example implementation to test, and if your `prebid.js` file is sourced from the `./build/dev` +directory you will have sourcemaps available in your browser's developer tools. To run the example file, go to: + `http://localhost:9999/integrationExamples/gpt/pbjs_example_gpt.html` -To view a test coverage report, go to: - -+ `http://localhost:9999/build/coverage/karma_html/report` - -A watch is also in place that will run continuous tests in the terminal as you edit code and tests. +As you make code changes, the bundles will be rebuilt and the page reloaded automatically. @@ -181,19 +205,21 @@ A watch is also in place that will run continuous tests in the terminal as you e Many SSPs, bidders, and publishers have contributed to this project. [60+ Bidders](https://github.com/prebid/Prebid.js/tree/master/src/adapters) are supported by Prebid.js. +For guidelines, see [Contributing](./CONTRIBUTING.md). + Our PR review process can be found [here](https://github.com/prebid/Prebid.js/tree/master/pr_review.md). ### Add a Bidder Adapter -To add a bidder adapter, see the instructions in [How to add a bidder adaptor](http://prebid.org/dev-docs/bidder-adaptor.html). +To add a bidder adapter module, see the instructions in [How to add a bidder adaptor](http://prebid.org/dev-docs/bidder-adaptor.html). Please **do NOT load Prebid.js inside your adapter**. If you do this, we will reject or remove your adapter as appropriate. ### Code Quality -Code quality is defined by `.jscs` and `.jshint` files and errors are reported in the terminal. +Code quality is defined by `.eslintrc` and errors are reported in the terminal. -If you are contributing code, you should configure your editor with the provided `.jscs` and `.jshint` settings. +If you are contributing code, you should [configure your editor](http://eslint.org/docs/user-guide/integrations#editors) with the provided `.eslintrc` settings. ### Unit Testing with Karma @@ -221,7 +247,7 @@ For instructions on writing tests for Prebid.js, see [Testing Prebid.js](http:// ### Supported Browsers -Prebid.js is supported on IE9+ and modern browsers. +Prebid.js is supported on IE10+ and modern browsers. ### Governance Review our governance model [here](https://github.com/prebid/Prebid.js/tree/master/governance.md). diff --git a/adapters.json b/adapters.json index 44e70d432b2..e69de29bb2d 100644 --- a/adapters.json +++ b/adapters.json @@ -1,146 +0,0 @@ -[ - "aardvark", - "adblade", - "adbund", - "adbutler", - "adequant", - "adform", - "adkernel", - "admedia", - "bidfluence", - "vertamedia", - "aol", - "appnexus", - "appnexusAst", - "beachfront", - "audienceNetwork", - "conversant", - "districtmDMX", - "fidelity", - "gumgum", - "hiromedia", - "indexExchange", - "innity", - "kruxlink", - "getintent", - "inneractive", - "komoona", - "lifestreet", - "mantis", - "openx", - "piximedia", - "pubmatic", - "pubgears", - "pulsepoint", - "pulsepointLite", - "quantcast", - "rhythmone", - "rubicon", - "smartyads", - "huddledmasses", - "smartadserver", - "sekindoUM", - "serverbid", - "sonobi", - "sovrn", - "springserve", - "thoughtleadr", - "stickyadstv", - "triplelift", - "twenga", - "yieldbot", - "nginad", - "brightcom", - "wideorbit", - "jcm", - "underdogmedia", - "memeglobal", - "criteo", - "centro", - "xhb", - "sharethrough", - "roxot", - "vertoz", - "widespace", - "admixer", - "atomx", - "tapsense", - "trion", - "prebidServer", - "adsupply", - { - "appnexus": { - "alias": "brealtime" - } - }, - { - "appnexus": { - "alias": "pagescience" - } - }, - { - "appnexus": { - "alias": "defymedia" - } - }, - { - "appnexus": { - "alias": "gourmetads" - } - }, - { - "appnexusAst": { - "supportedMediaTypes": ["video"] - } - }, { - "vertamedia": { - "supportedMediaTypes": ["video"] - } - }, - { - "beachfront": { - "supportedMediaTypes": ["video"] - } - }, - { - "appnexus": { - "alias": "matomy" - } - }, - { - "rubicon": { - "alias": "rubiconLite", - "supportedMediaTypes": ["video"] - } - }, - { - "appnexus": { - "alias": "featureforward" - } - }, - { - "appnexus": { - "alias": "oftmedia" - } - }, - { - "adkernel": { - "alias": "headbidding" - } - }, - { - "getintent": { - "supportedMediaTypes" : ["video"] - } - }, - { - "stickyadstv": { - "alias": "freewheel-ssp" - } - }, - { - "rhythmone": { - "supportedMediaTypes": ["video"] - } - } -] diff --git a/analytics.json b/analytics.json index 36506bd9a4a..e69de29bb2d 100644 --- a/analytics.json +++ b/analytics.json @@ -1 +0,0 @@ -["aol"] diff --git a/browsers.json b/browsers.json index 85bbc6b10b0..5198bb48bbb 100644 --- a/browsers.json +++ b/browsers.json @@ -1,230 +1,8 @@ { - "bs_ie_13_windows_10": { + "bs_chrome_win8": { "base": "BrowserStack", - "os_version": "10", - "browser": "edge", - "browser_version": "13.0", - "device": null, - "os": "Windows" - }, - "bs_ie_11_windows_10": { - "base": "BrowserStack", - "os_version": "10", - "browser": "ie", - "browser_version": "11.0", - "device": null, - "os": "Windows" - }, - "bs_firefox_46_windows_10": { - "base": "BrowserStack", - "os_version": "10", - "browser": "firefox", - "browser_version": "46.0", - "device": null, - "os": "Windows" - }, - "bs_chrome_51_windows_10": { - "base": "BrowserStack", - "os_version": "10", - "browser": "chrome", - "browser_version": "51.0", - "device": null, - "os": "Windows" - }, - "bs_ie_11_windows_8.1": { - "base": "BrowserStack", - "os_version": "8.1", - "browser": "ie", - "browser_version": "11.0", - "device": null, - "os": "Windows" - }, - "bs_firefox_46_windows_8.1": { - "base": "BrowserStack", - "os_version": "8.1", - "browser": "firefox", - "browser_version": "46.0", - "device": null, - "os": "Windows" - }, - "bs_chrome_51_windows_8.1": { - "base": "BrowserStack", - "os_version": "8.1", - "browser": "chrome", - "browser_version": "51.0", - "device": null, - "os": "Windows" - }, - "bs_ie_10_windows_8": { - "base": "BrowserStack", - "os_version": "8", - "browser": "ie", - "browser_version": "10.0", - "device": null, - "os": "Windows" - }, - "bs_firefox_46_windows_8": { - "base": "BrowserStack", - "os_version": "8", - "browser": "firefox", - "browser_version": "46.0", - "device": null, - "os": "Windows" - }, - "bs_chrome_51_windows_8": { - "base": "BrowserStack", - "os_version": "8", - "browser": "chrome", - "browser_version": "51.0", - "device": null, - "os": "Windows" - }, - "bs_ie_11_windows_7": { - "base": "BrowserStack", - "os_version": "7", - "browser": "ie", - "browser_version": "11.0", - "device": null, - "os": "Windows" - }, - "bs_ie_10_windows_7": { - "base": "BrowserStack", - "os_version": "7", - "browser": "ie", - "browser_version": "10.0", - "device": null, - "os": "Windows" - }, - "bs_ie_9_windows_7": { - "base": "BrowserStack", - "os_version": "7", - "browser": "ie", - "browser_version": "9.0", - "device": null, - "os": "Windows" - }, - "bs_firefox_46_windows_7": { - "base": "BrowserStack", - "os_version": "7", - "browser": "firefox", - "browser_version": "46.0", - "device": null, - "os": "Windows" - }, - "bs_chrome_51_windows_7": { - "base": "BrowserStack", - "os_version": "7", "browser": "chrome", - "browser_version": "51.0", - "device": null, - "os": "Windows" - }, - "bs_chrome_56_mac_sierra": { - "base": "BrowserStack", - "os": "OS X", - "os_version": "Sierra", - "browser": "chrome", - "device": null, - "browser_version": "56.0" - }, - "bs_safari_9.1_mac_elcapitan": { - "base": "BrowserStack", - "os_version": "El Capitan", - "browser": "safari", - "browser_version": "9.1", - "device": null, - "os": "OS X" - }, - "bs_firefox_46_mac_elcapitan": { - "base": "BrowserStack", - "os_version": "El Capitan", - "browser": "firefox", - "browser_version": "46.0", - "device": null, - "os": "OS X" - }, - "bs_chrome_51_mac_elcapitan": { - "base": "BrowserStack", - "os_version": "El Capitan", - "browser": "chrome", - "browser_version": "51.0", - "device": null, - "os": "OS X" - }, - "bs_safari_8_mac_yosemite": { - "base": "BrowserStack", - "os_version": "Yosemite", - "browser": "safari", - "browser_version": "8.0", - "device": null, - "os": "OS X" - }, - "bs_firefox_46_mac_yosemite": { - "base": "BrowserStack", - "os_version": "Yosemite", - "browser": "firefox", - "browser_version": "46.0", - "device": null, - "os": "OS X" - }, - "bs_chrome_51_mac_yosemite": { - "base": "BrowserStack", - "os_version": "Yosemite", - "browser": "chrome", - "browser_version": "51.0", - "device": null, - "os": "OS X" - }, - "bs_safari_7.1_mac_mavericks": { - "base": "BrowserStack", - "os_version": "Mavericks", - "browser": "safari", - "browser_version": "7.1", - "device": null, - "os": "OS X" - }, - "bs_firefox_46_mac_mavericks": { - "base": "BrowserStack", - "os_version": "Mavericks", - "browser": "firefox", - "browser_version": "46.0", - "device": null, - "os": "OS X" - }, - "bs_chrome_49_mac_mavericks": { - "base": "BrowserStack", - "os_version": "Mavericks", - "browser": "chrome", - "browser_version": "49.0", - "device": null, - "os": "OS X" - }, - "bs_ios_7": { - "base": "BrowserStack", - "os": "ios", - "os_version": "7.0", - "browser": "iphone", - "device": "iPhone 5S", - "browser_version": null - }, - "bs_ios_8": { - "base": "BrowserStack", - "os": "ios", - "os_version": "8.3", - "browser": "iphone", - "device": "iPhone 6", - "browser_version": null - }, - "bs_ios_9": { - "base": "BrowserStack", - "os": "ios", - "os_version": "9.1", - "browser": "iphone", - "device": "iPhone 6S", - "browser_version": null - }, - "Chrome_travis_ci": { - "base": "Chrome", - "flags": ["--no-sandbox"] + "os": "Windows", + "os_version": "8.1" } } diff --git a/governance.md b/governance.md index faaece83079..9f8a1fe1e13 100644 --- a/governance.md +++ b/governance.md @@ -20,3 +20,4 @@ This document describes the governance model for the Prebid project. The Prebid - @jaiminpanchal27 - @snapwich - @harpere +- @dbemiller diff --git a/gulpHelpers.js b/gulpHelpers.js index 6091dc4c495..9ca2d242d81 100644 --- a/gulpHelpers.js +++ b/gulpHelpers.js @@ -4,6 +4,26 @@ const path = require('path'); const argv = require('yargs').argv; const MANIFEST = 'package.json'; const exec = require('child_process').exec; +const through = require('through2'); +const _ = require('lodash'); +const gutil = require('gulp-util'); + +const MODULE_PATH = './modules'; +const BUILD_PATH = './build/dist'; +const DEV_PATH = './build/dev'; + + +// get only subdirectories that contain package.json with 'main' property +function isModuleDirectory(filePath) { + try { + const manifestPath = path.join(filePath, MANIFEST); + if (fs.statSync(manifestPath).isFile()) { + const module = require(manifestPath); + return module && module.main; + } + } + catch (error) {} +} module.exports = { parseBrowserArgs: function (argv) { @@ -20,6 +40,85 @@ module.exports = { .replace(/<\//g, '<\\/') .replace(/\/>/g, '\\/>'); }, + getArgModules() { + var modules = (argv.modules || '').split(',').filter(module => !!module); + + try { + if (modules.length === 1 && path.extname(modules[0]).toLowerCase() === '.json') { + var moduleFile = modules[0]; + + modules = JSON.parse( + fs.readFileSync(moduleFile, 'utf8') + ); + } + } catch(e) { + throw new gutil.PluginError({ + plugin: 'modules', + message: 'failed reading: ' + argv.modules + }); + } + + return modules; + }, + getModules: _.memoize(function(externalModules) { + externalModules = externalModules || []; + var internalModules; + try { + internalModules = fs.readdirSync(MODULE_PATH) + .filter(file => !(/(^|\/)\.[^\/\.]/g).test(file)) + .reduce((memo, file) => { + var moduleName = file.split(new RegExp('[.\\' + path.sep + ']'))[0]; + var filePath = path.join(MODULE_PATH, file); + var modulePath = path.join(__dirname, filePath) + if (fs.lstatSync(filePath).isDirectory()) { + modulePath = path.join(__dirname, filePath, "index.js") + } + memo[modulePath] = moduleName; + return memo; + }, {}); + } catch(err) { + internalModules = {}; + } + return Object.assign(externalModules.reduce((memo, module) => { + try { + var modulePath = require.resolve(module); + memo[modulePath] = module; + } catch(err) { + // do something + } + return memo; + }, internalModules)); + }), + + getBuiltModules: function(dev, externalModules) { + var modules = this.getModuleNames(externalModules); + if(Array.isArray(externalModules)) { + modules = _.intersection(modules, externalModules); + } + return modules.map(name => path.join(__dirname, dev ? DEV_PATH : BUILD_PATH, name + '.js')); + }, + + getBuiltPrebidCoreFile: function(dev) { + return path.join(__dirname, dev ? DEV_PATH : BUILD_PATH, 'prebid-core' + '.js'); + }, + + getModulePaths: function(externalModules) { + var modules = this.getModules(externalModules); + return Object.keys(modules); + }, + + getModuleNames: function(externalModules) { + return _.values(this.getModules(externalModules)); + }, + + nameModules: function(externalModules) { + var modules = this.getModules(externalModules); + return through.obj(function(file, enc, done) { + file.named = modules[file.path] ? modules[file.path] : 'prebid'; + this.push(file); + done(); + }) + }, /* * Get source files for analytics subdirectories in top-level `analytics` @@ -37,18 +136,6 @@ module.exports = { const module = require(path.join(directory, moduleDirectory, MANIFEST)); return path.join(directory, moduleDirectory, module.main); }); - - // get only subdirectories that contain package.json with 'main' property - function isModuleDirectory(filePath) { - try { - const manifestPath = path.join(filePath, MANIFEST); - if (fs.statSync(manifestPath).isFile()) { - const module = require(manifestPath); - return module && module.main; - } - } - catch (error) {} - } }, createEnd2EndTestReport : function(targetDestinationDir) { diff --git a/gulpfile.js b/gulpfile.js index 1caafb647f1..a99074caded 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -1,46 +1,48 @@ 'use strict'; +var _ = require('lodash'); var argv = require('yargs').argv; var gulp = require('gulp'); var gutil = require('gulp-util'); var connect = require('gulp-connect'); -var webpack = require('webpack-stream'); +var path = require('path'); +var webpack = require('webpack'); +var webpackStream = require('webpack-stream'); var uglify = require('gulp-uglify'); -var jshint = require('gulp-jshint'); var clean = require('gulp-clean'); -var karma = require('gulp-karma'); -var mocha = require('gulp-mocha'); +var KarmaServer = require('karma').Server; +var karmaConfMaker = require('./karma.conf.maker'); var opens = require('open'); -var webpackConfig = require('./webpack.conf.js'); +var webpackConfig = require('./webpack.conf'); var helpers = require('./gulpHelpers'); var del = require('del'); var gulpJsdoc2md = require('gulp-jsdoc-to-markdown'); var concat = require('gulp-concat'); -var jscs = require('gulp-jscs'); var header = require('gulp-header'); -var zip = require('gulp-zip'); +var footer = require('gulp-footer'); var replace = require('gulp-replace'); var shell = require('gulp-shell'); var optimizejs = require('gulp-optimize-js'); +var eslint = require('gulp-eslint'); +var gulpif = require('gulp-if'); +var sourcemaps = require('gulp-sourcemaps'); +var fs = require('fs'); -var CI_MODE = process.env.NODE_ENV === 'ci'; var prebid = require('./package.json'); -var dateString = 'Updated: ' + (new Date()).toISOString().substring(0, 10); -var packageNameVersion = prebid.name + '_' + prebid.version; -var banner = '/* <%= prebid.name %> v<%= prebid.version %>, ' + dateString + ' */\n'; +var banner = '/* <%= prebid.name %> v<%= prebid.version %>*/\n'; var analyticsDirectory = '../analytics'; var port = 9999; // Tasks -gulp.task('default', ['clean', 'quality', 'webpack']); +gulp.task('default', ['webpack']); -gulp.task('serve', ['clean', 'quality', 'devpack', 'webpack', 'watch', 'test']); +gulp.task('serve', ['lint', 'build-bundle-dev', 'watch', 'test']); -gulp.task('serve-nw', ['clean', 'quality', 'devpack', 'webpack', 'watch', 'e2etest']); +gulp.task('serve-nw', ['lint', 'watch', 'e2etest']); -gulp.task('run-tests', ['clean', 'quality', 'webpack', 'test', 'mocha']); +gulp.task('run-tests', ['lint', 'test-coverage']); -gulp.task('build', ['webpack']); +gulp.task('build', ['build-bundle-prod']); gulp.task('clean', function () { return gulp.src(['build'], { @@ -49,158 +51,168 @@ gulp.task('clean', function () { .pipe(clean()); }); -gulp.task('devpack', function () { - webpackConfig.devtool = 'source-map'; +function bundle(dev) { + var modules = helpers.getArgModules(), + allModules = helpers.getModuleNames(modules); + + if(modules.length === 0) { + modules = allModules; + } else { + var diff = _.difference(modules, allModules); + if(diff.length !== 0) { + throw new gutil.PluginError({ + plugin: 'bundle', + message: 'invalid modules: ' + diff.join(', ') + }); + } + } + + var entries = [helpers.getBuiltPrebidCoreFile(dev)].concat(helpers.getBuiltModules(dev, modules)); + + gutil.log('Concatenating files:\n', entries); + gutil.log('Appending ' + prebid.globalVarName + '.processQueue();'); + + return gulp.src( + entries + ) + .pipe(gulpif(dev, sourcemaps.init({loadMaps: true}))) + .pipe(concat(argv.bundleName ? argv.bundleName : 'prebid.js')) + .pipe(gulpif(!argv.manualEnable, footer('\n<%= global %>.processQueue();', { + global: prebid.globalVarName + } + ))) + .pipe(gulpif(dev, sourcemaps.write('.'))) + .pipe(gulp.dest('build/' + (dev ? 'dev' : 'dist'))); +} + +// Workaround for incompatibility between Karma & gulp callbacks. +// See https://github.com/karma-runner/gulp-karma/issues/18 for some related discussion. +function newKarmaCallback(done) { + return function (exitCode) { + if (exitCode) { + done(new Error('Karma tests failed with exit code ' + exitCode)); + } else { + done(); + } + } +} + +gulp.task('build-bundle-dev', ['devpack'], bundle.bind(null, true)); +gulp.task('build-bundle-prod', ['webpack'], bundle.bind(null, false)); +gulp.task('bundle', bundle.bind(null, false)); // used for just concatenating pre-built files with no build step + +gulp.task('devpack', ['clean'], function () { + var cloned = _.cloneDeep(webpackConfig); + cloned.devtool = 'source-map'; + var externalModules = helpers.getArgModules(); + const analyticsSources = helpers.getAnalyticsSources(analyticsDirectory); - return gulp.src([].concat(analyticsSources, 'src/prebid.js')) - .pipe(webpack(webpackConfig)) + const moduleSources = helpers.getModulePaths(externalModules); + + return gulp.src([].concat(moduleSources, analyticsSources, 'src/prebid.js')) + .pipe(helpers.nameModules(externalModules)) + .pipe(webpackStream(cloned, webpack)) .pipe(replace('$prebid.version$', prebid.version)) - // Remove window=window that was used to go around Uglify bug - .pipe(replace(/window\s*=\s*window;/g, '')) .pipe(gulp.dest('build/dev')) .pipe(connect.reload()); }); -gulp.task('webpack', function () { +gulp.task('webpack', ['clean'], function () { + var cloned = _.cloneDeep(webpackConfig); // change output filename if argument --tag given if (argv.tag && argv.tag.length) { - webpackConfig.output.filename = 'prebid.' + argv.tag + '.js'; + cloned.output.filename = 'prebid.' + argv.tag + '.js'; } - webpackConfig.devtool = null; + delete cloned.devtool; - webpackConfig.module.loaders = webpackConfig.module.loaders.concat([{ - test: /adapters/, - include: /(src)/, - exclude: /(adapter.js|baseAdapter.js|analytics)/, - loader: 'delimiterLoader' - }]); + var externalModules = helpers.getArgModules(); const analyticsSources = helpers.getAnalyticsSources(analyticsDirectory); - return gulp.src([].concat(analyticsSources, 'src/prebid.js')) - .pipe(webpack(webpackConfig)) + const moduleSources = helpers.getModulePaths(externalModules); + + return gulp.src([].concat(moduleSources, analyticsSources, 'src/prebid.js')) + .pipe(helpers.nameModules(externalModules)) + .pipe(webpackStream(cloned, webpack)) .pipe(replace('$prebid.version$', prebid.version)) - .pipe(uglify({ - preserveComments: 'some', - compress: { - // Hoisting of the functions turned off to prevent code movement. - // This prevents comment blocks delimiting the definition of the adapters from being moved - // so it fixes the extraction of the adapters during the build. - hoist_funs: false - } - })) - .pipe(header(banner, { prebid: prebid })) + .pipe(uglify()) + .pipe(gulpif(file => file.basename === 'prebid-core.js', header(banner, { prebid: prebid }))) .pipe(optimizejs()) - // Remove window=window that was used to go around Uglify bug - .pipe(replace(/,?(\/\*!ADAPTER BEGIN \w+\*\/)\s*window\s*=\s*window/g, '$1')) - .pipe(replace(/,?(\/\*!ADAPTER END \w+\*\/)\s*window\s*=\s*window/g, '$1')) .pipe(gulp.dest('build/dist')) .pipe(connect.reload()); }); -//zip up for release -gulp.task('zip', ['jscs', 'clean', 'webpack'], function () { - return gulp.src(['build/dist/*', 'integrationExamples/gpt/*']) - .pipe(zip(packageNameVersion + '.zip')) - .pipe(gulp.dest('./')); +gulp.task('build-aol-bundle', ['build-bundle-dev'], () => { + return gulp.src('build/dev/prebid.js') + .pipe(replace(/(\/\*!(ANALYTICS\s)?ADAPTER BEGIN \w+\*\/)/g, '$1window=window;')) + .pipe(replace(/(\/\*!(ANALYTICS\s)?ADAPTER END \w+\*\/)/g, '$1window=window;')) + .pipe(uglify({ + output: { + comments: /^!/ + } + })) + .pipe(optimizejs()) + .pipe(replace(/(\/\*!(ANALYTICS\s)?ADAPTER BEGIN \w+\*\/)\s*window=window(;|,)?/g, '$1')) + .pipe(replace(/(,)?(\/\*!(ANALYTICS\s)?ADAPTER END \w+\*\/)\s*window=window(;|,)?/g, ';$2')) + .pipe(header(banner, { prebid: prebid })) + .pipe(gulp.dest('build/dist')); }); -// Karma Continuous Testing -// Pass your browsers by using --browsers=chrome,firefox,ie9 -// Run CI by passing --watch -gulp.task('test', function () { - var defaultBrowsers = CI_MODE ? ['PhantomJS'] : ['Chrome']; - var browserArgs = helpers.parseBrowserArgs(argv).map(helpers.toCapitalCase); - - if (process.env.TRAVIS) { - browserArgs = ['Chrome_travis_ci']; +// Run the unit tests. +// +// By default, this runs in headless chrome. +// +// If --watch is given, the task will re-run unit tests whenever the source code changes +// If --browserstack is given, it will run the full suite of currently supported browsers. +// If --browsers is given, browsers can be chosen explicitly. e.g. --browsers=chrome,firefox,ie9 +gulp.task('test', ['clean'], function (done) { + var karmaConf = karmaConfMaker(false, argv.browserstack, argv.watch); + + var browserOverride = helpers.parseBrowserArgs(argv).map(helpers.toCapitalCase); + if (browserOverride.length > 0) { + karmaConf.browsers = browserOverride; } - if (argv.browserstack) { - browserArgs = [ - 'bs_ie_13_windows_10', - 'bs_ie_11_windows_10', - 'bs_firefox_46_windows_10', - 'bs_chrome_51_windows_10', - 'bs_ie_11_windows_8.1', - 'bs_firefox_46_windows_8.1', - 'bs_chrome_51_windows_8.1', - 'bs_ie_10_windows_8', - 'bs_firefox_46_windows_8', - 'bs_chrome_51_windows_8', - 'bs_ie_11_windows_7', - 'bs_ie_10_windows_7', - 'bs_ie_9_windows_7', - 'bs_firefox_46_windows_7', - 'bs_chrome_51_windows_7', - 'bs_safari_9.1_mac_elcapitan', - 'bs_firefox_46_mac_elcapitan', - 'bs_chrome_51_mac_elcapitan', - 'bs_safari_8_mac_yosemite', - 'bs_firefox_46_mac_yosemite', - 'bs_chrome_51_mac_yosemite', - 'bs_safari_7.1_mac_mavericks', - 'bs_firefox_46_mac_mavericks', - 'bs_chrome_49_mac_mavericks', - 'bs_ios_7', - 'bs_ios_8', - 'bs_ios_9', - ]; - } - - return gulp.src('lookAtKarmaConfJS') - .pipe(karma({ - browsers: (browserArgs.length > 0) ? browserArgs : defaultBrowsers, - configFile: 'karma.conf.js', - action: (argv.watch) ? 'watch' : 'run' - })); + new KarmaServer(karmaConf, newKarmaCallback(done)).start(); }); -gulp.task('mocha', ['webpack'], function() { - return gulp.src(['test/spec/loaders/**/*.js'], { read: false }) - .pipe(mocha({ - reporter: 'spec', - globals: { - expect: require('chai').expect - } - })) - .on('error', gutil.log); +gulp.task('test-coverage', ['clean'], function(done) { + new KarmaServer(karmaConfMaker(true, false), newKarmaCallback(done)).start(); }); -// Small task to load coverage reports in the browser -gulp.task('coverage', function (done) { +// View the code coverage report in the browser. +gulp.task('view-coverage', function (done) { var coveragePort = 1999; connect.server({ - port: 1999, - root: 'build/coverage', + port: coveragePort, + root: 'build/coverage/karma_html', livereload: false }); - opens('http://localhost:' + coveragePort + '/coverage/'); + opens('http://localhost:' + coveragePort); done(); }); -gulp.task('coveralls', ['test'], function() { // 2nd arg is a dependency: 'test' must be finished +gulp.task('coveralls', ['test-coverage'], function() { // 2nd arg is a dependency: 'test' must be finished // first send results of istanbul's test coverage to coveralls.io. return gulp.src('gulpfile.js', { read: false }) // You have to give it a file, but you don't // have to read it. - .pipe(shell('cat build/coverage/lcov/lcov.info | node_modules/coveralls/bin/coveralls.js')); + .pipe(shell('cat build/coverage/lcov.info | node_modules/coveralls/bin/coveralls.js')); }); // Watch Task with Live Reload gulp.task('watch', function () { - gulp.watch([ 'src/**/*.js', + 'modules/**/*.js', 'test/spec/**/*.js', '!test/spec/loaders/**/*.js' - ], ['quality', 'webpack', 'devpack', 'test']); + ], ['lint', 'build-bundle-dev', 'test']); gulp.watch([ 'loaders/**/*.js', 'test/spec/loaders/**/*.js' - ], ['quality', 'mocha']); - gulp.watch(['integrationExamples/gpt/*.html'], ['test']); + ], ['lint']); connect.server({ https: argv.https, port: port, @@ -209,21 +221,11 @@ gulp.task('watch', function () { }); }); -gulp.task('quality', ['hint', 'jscs']); - -gulp.task('hint', function () { - return gulp.src('src/**/*.js') - .pipe(jshint('.jshintrc')) - .pipe(jshint.reporter('jshint-stylish')) - .pipe(jshint.reporter('fail')); -}); - -gulp.task('jscs', function () { - return gulp.src('src/**/*.js') - .pipe(jscs({ - configPath: '.jscsrc' - })) - .pipe(jscs.reporter()); +gulp.task('lint', () => { + return gulp.src(['src/**/*.js', 'modules/**/*.js', 'test/**/*.js']) + .pipe(eslint()) + .pipe(eslint.format('stylish')) + .pipe(eslint.failAfterError()); }); gulp.task('clean-docs', function () { @@ -240,7 +242,7 @@ gulp.task('docs', ['clean-docs'], function () { .pipe(gulp.dest('docs')); }); -gulp.task('e2etest', function() { +gulp.task('e2etest', ['devpack', 'webpack'], function() { var cmdQueue = []; if(argv.browserstack) { var browsers = require('./browsers.json'); @@ -282,5 +284,10 @@ gulp.task('e2etest-report', function() { setTimeout(function() { opens('http://localhost:' + reportPort + '/' + targetDestinationDir.slice(2) + '/results.html'); }, 5000); +}); +gulp.task('build-postbid', function() { + return gulp.src('./integrationExamples/postbid/oas/postbid.js') + .pipe(uglify()) + .pipe(gulp.dest('build/dist')); }); diff --git a/integrationExamples/gpt/.gitignore b/integrationExamples/gpt/.gitignore deleted file mode 100644 index fb64ad0cc6e..00000000000 --- a/integrationExamples/gpt/.gitignore +++ /dev/null @@ -1 +0,0 @@ -pbjs_adblade_example_gpt.html diff --git a/integrationExamples/gpt/amp/amp_page.html b/integrationExamples/gpt/amp/amp_page.html index 2e2931e9dd6..ac6a2bcd3fe 100644 --- a/integrationExamples/gpt/amp/amp_page.html +++ b/integrationExamples/gpt/amp/amp_page.html @@ -55,7 +55,7 @@

Welcome to the mobile web

height="250" layout="fixed" type="doubleclick" - json='{"prebid":{"requestBidsDuration":1000,"adUnits":[{"code":"/19968336/header-bid-tag-1","sizes":[[300,250],[300,600],[300,250],[100,100]],"bids":[{"bidder":"appnexusAst","params":{"placementId":"4799418","dealId":"some deal!"}},{"bidder":"aol","params":{"network":"10077.1","placement":3671670}},{"bidder":"sovrn","params":{"tagid":"315045"}}]},{"code":"/19968336/header-bid-tag-2","sizes":[[300,250],[300,600],[300,250],[100,100]],"bids":[{"bidder":"appnexusAst","params":{"placementId":"4799418","dealId":"some deal!"}},{"bidder":"aol","params":{"network":"10077.1","placement":3671670}},{"bidder":"sovrn","params":{"tagid":"315045"}}]}]}}' + json='{"prebid":{"requestBidsDuration":1000,"adUnits":[{"code":"/19968336/header-bid-tag-1","sizes":[[300,250],[300,600],[300,250],[100,100]],"bids":[{"bidder":"appnexusAst","params":{"placementId":"10433394","dealId":"some deal!"}},{"bidder":"aol","params":{"network":"10077.1","placement":3671670}},{"bidder":"sovrn","params":{"tagid":"315045"}}]},{"code":"/19968336/header-bid-tag-2","sizes":[[300,250],[300,600],[300,250],[100,100]],"bids":[{"bidder":"appnexusAst","params":{"placementId":"10433394","dealId":"some deal!"}},{"bidder":"aol","params":{"network":"10077.1","placement":3671670}},{"bidder":"sovrn","params":{"tagid":"315045"}}]}]}}' data-slot="/19968336/header-bid-tag-1"> @@ -64,7 +64,7 @@

Welcome to the mobile web

height="250" layout="fixed" type="doubleclick" - json='{"prebid":{"requestBidsDuration":1000,"adUnits":[{"code":"/19968336/header-bid-tag-1","sizes":[[300,250],[300,600],[300,250],[100,100]],"bids":[{"bidder":"appnexusAst","params":{"placementId":"4799418","dealId":"some deal!"}},{"bidder":"aol","params":{"network":"10077.1","placement":3671670}},{"bidder":"sovrn","params":{"tagid":"315045"}}]},{"code":"/19968336/header-bid-tag-2","sizes":[[300,250],[300,600],[300,250],[100,100]],"bids":[{"bidder":"appnexusAst","params":{"placementId":"4799418","dealId":"some deal!"}},{"bidder":"aol","params":{"network":"10077.1","placement":3671670}},{"bidder":"sovrn","params":{"tagid":"315045"}}]}]}}' + json='{"prebid":{"requestBidsDuration":1000,"adUnits":[{"code":"/19968336/header-bid-tag-1","sizes":[[300,250],[300,600],[300,250],[100,100]],"bids":[{"bidder":"appnexusAst","params":{"placementId":"10433394","dealId":"some deal!"}},{"bidder":"aol","params":{"network":"10077.1","placement":3671670}},{"bidder":"sovrn","params":{"tagid":"315045"}}]},{"code":"/19968336/header-bid-tag-2","sizes":[[300,250],[300,600],[300,250],[100,100]],"bids":[{"bidder":"appnexusAst","params":{"placementId":"10433394","dealId":"some deal!"}},{"bidder":"aol","params":{"network":"10077.1","placement":3671670}},{"bidder":"sovrn","params":{"tagid":"315045"}}]}]}}' data-slot="/19968336/header-bid-tag-2"> diff --git a/integrationExamples/gpt/amp/remote.html b/integrationExamples/gpt/amp/remote.html index 5b604c88a6b..40404636061 100644 --- a/integrationExamples/gpt/amp/remote.html +++ b/integrationExamples/gpt/amp/remote.html @@ -25,7 +25,7 @@ diff --git a/integrationExamples/gpt/gpt_aliasingBidder.html b/integrationExamples/gpt/gpt_aliasingBidder.html index 203b81be876..f9c7120079d 100644 --- a/integrationExamples/gpt/gpt_aliasingBidder.html +++ b/integrationExamples/gpt/gpt_aliasingBidder.html @@ -18,7 +18,7 @@ if ($$PREBID_GLOBAL$$.initAdserverSet) return; googletag.cmd.push(function () { - $$PREBID_GLOBAL$$.que.push(function () { + $$PREBID_GLOBAL$$.cmd.push(function () { $$PREBID_GLOBAL$$.setTargetingForGPTAsync(); googletag.pubads().refresh(); }); @@ -30,7 +30,7 @@ setTimeout(initAdserver, PREBID_TIMEOUT); var $$PREBID_GLOBAL$$ = $$PREBID_GLOBAL$$ || {}; - $$PREBID_GLOBAL$$.que = $$PREBID_GLOBAL$$.que || []; + $$PREBID_GLOBAL$$.cmd = $$PREBID_GLOBAL$$.cmd || []; // Load the Prebid Javascript Library Async. We recommend loading it immediately after // the initAdserver() and setTimeout functions. @@ -54,7 +54,7 @@ node.parentNode.insertBefore(gads, node); })(); - $$PREBID_GLOBAL$$.que.push(function () { + $$PREBID_GLOBAL$$.cmd.push(function () { var adUnits = [ { code: 'div-gpt-ad-12345678-0', @@ -177,7 +177,7 @@

Prebid.js Test

ga('create', 'XXXXXX', 'auto'); //Send data from prebid.js automatically - $$PREBID_GLOBAL$$.que.push(function () { + $$PREBID_GLOBAL$$.cmd.push(function () { $$PREBID_GLOBAL$$.enableAnalytics({ provider: 'ga', options: { diff --git a/integrationExamples/gpt/hello_world.html b/integrationExamples/gpt/hello_world.html new file mode 100644 index 00000000000..0f5e24a301a --- /dev/null +++ b/integrationExamples/gpt/hello_world.html @@ -0,0 +1,102 @@ + + + + + + + + + + + + + + + +

Prebid.js Test

+
Div-1
+
+ +
+ + diff --git a/integrationExamples/gpt/pbjs_example_gpt.html b/integrationExamples/gpt/pbjs_example_gpt.html index 2380db9fc29..a7ee24c059e 100644 --- a/integrationExamples/gpt/pbjs_example_gpt.html +++ b/integrationExamples/gpt/pbjs_example_gpt.html @@ -1,556 +1,556 @@ - - - -Prebid.js integration example - - - - -

Prebid.js Test

- -
- -
- - -
- -
- - - - - - - + + + +Prebid.js integration example + + + + +

Prebid.js Test

+ +
+ +
+ + +
+ +
+ + + + + + + diff --git a/integrationExamples/gpt/pbjs_partial_refresh_gpt.html b/integrationExamples/gpt/pbjs_partial_refresh_gpt.html index 6fc9356e4cb..09009a24d76 100644 --- a/integrationExamples/gpt/pbjs_partial_refresh_gpt.html +++ b/integrationExamples/gpt/pbjs_partial_refresh_gpt.html @@ -19,7 +19,7 @@ if ($$PREBID_GLOBAL$$.initAdserverSet) return; googletag.cmd.push(function () { - $$PREBID_GLOBAL$$.que.push(function () { + $$PREBID_GLOBAL$$.cmd.push(function () { $$PREBID_GLOBAL$$.setTargetingForGPTAsync(); googletag.pubads().refresh(); }); @@ -31,7 +31,7 @@ setTimeout(initAdserver, PREBID_TIMEOUT); var $$PREBID_GLOBAL$$ = $$PREBID_GLOBAL$$ || {}; - $$PREBID_GLOBAL$$.que = $$PREBID_GLOBAL$$.que || []; + $$PREBID_GLOBAL$$.cmd = $$PREBID_GLOBAL$$.cmd || []; // Load the Prebid Javascript Library Async. We recommend loading it immediately after // the initAdserver() and setTimeout functions. @@ -43,7 +43,7 @@ target.insertBefore(pbs, target.firstChild); })(); - $$PREBID_GLOBAL$$.que.push(function () { + $$PREBID_GLOBAL$$.cmd.push(function () { /* 1. Register bidder tag Ids @@ -230,7 +230,7 @@ }); function refreshBid1() { - $$PREBID_GLOBAL$$.que.push(function () { + $$PREBID_GLOBAL$$.cmd.push(function () { $$PREBID_GLOBAL$$.requestBids({ timeout: PREBID_TIMEOUT, adUnitCodes: ['/9968336/header-bid-tag-0'], @@ -243,7 +243,7 @@ } function refreshBid2() { - $$PREBID_GLOBAL$$.que.push(function () { + $$PREBID_GLOBAL$$.cmd.push(function () { $$PREBID_GLOBAL$$.requestBids({ timeout: PREBID_TIMEOUT, adUnitCodes: ['/9968336/header-bid-tag1'], diff --git a/integrationExamples/gpt/pbjs_ucfunnel_gpt.html b/integrationExamples/gpt/pbjs_ucfunnel_gpt.html new file mode 100644 index 00000000000..67881d7168d --- /dev/null +++ b/integrationExamples/gpt/pbjs_ucfunnel_gpt.html @@ -0,0 +1,99 @@ + + + + + + + + + + + + + + + + + + + + + +

Prebid.js Test

+
Div-1
+ + +
+ +
+ + + diff --git a/integrationExamples/postbid/oas/creative.html b/integrationExamples/postbid/oas/creative.html new file mode 100644 index 00000000000..76b16b0fa57 --- /dev/null +++ b/integrationExamples/postbid/oas/creative.html @@ -0,0 +1,69 @@ + +
+ diff --git a/integrationExamples/postbid/oas/postbid.js b/integrationExamples/postbid/oas/postbid.js new file mode 100644 index 00000000000..a4aeb588b26 --- /dev/null +++ b/integrationExamples/postbid/oas/postbid.js @@ -0,0 +1,118 @@ +(function(window){ + var postbid = {}; + postbid.que = []; + + var processQue = function(conf) { + for (var i = 0; i < postbid.que.length; i++) { + if (typeof postbid.que[i].called === 'undefined') { + try { + postbid.que[i].call(null, conf); + postbid.que[i].called = true; + } + catch (e) { + + } + } + } + } + + function getIframeContentDoc(iframe) { + var doc; + try { + if (iframe.contentWindow) { + doc = iframe.contentWindow.document; + } else if (iframe.contentDocument.document) { + doc = iframe.contentDocument.document; + } else { + doc = iframe.contentDocument; + } + } catch (e) { + } + return doc; + } + + function createIframe(id) { + var iframe = document.createElement('iframe'); + iframe.id = id; + iframe.width = '100%'; + iframe.height = '100%'; + iframe.frameBorder = "0"; + iframe.marginWidth = "0"; + iframe.marginHeight = "0"; + iframe.scrolling = "no"; + iframe.setAttribute('border', '0'); + iframe.setAttribute('allowtransparency', "true"); + + return iframe; + } + + function loadIframe(iframe, content) { + var iframeDoc = getIframeContentDoc(iframe); + iframeDoc.open('text/html', 'replace'); + iframeDoc.write(content); + iframeDoc.close(); + } + + function loadIeIframe(iframe, content) { + iframe.contentWindow.contents = content; + var base = document.getElementsByTagName('base'); + if(base.length) base[0].target = '_self'; + iframe.src = 'javascript:window["contents"];'; + if(base.length) base[0].target = '_blank'; + } + + function getBrowserType() { + var ua = navigator.userAgent.toLowerCase(); + + var match = /(webkit)[ \/]([\w.]+)/.exec(ua) || + /(opera)(?:.*version|)[ \/]([\w.]+)/.exec(ua) || + /(msie) ([\w.]+)/.exec(ua) || + /(trident)(\/\d.0);/.exec(ua) || + (/trident\/7.0;/.test(ua)) ? ['msie'] : false || + ua.indexOf('compatible') < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec(ua) || []; + + return match[1]; + } + + if (!Array.prototype.find) { + Object.defineProperty(Array.prototype, 'find', { + value: function(predicate) { + if (this == null) { + throw new TypeError('"this" is null or not defined'); + } + var o = Object(this); + var len = o.length >>> 0; + if (typeof predicate !== 'function') { + throw new TypeError('predicate must be a function'); + } + var thisArg = arguments[1]; + var k = 0; + while (k < len) { + var kValue = o[k]; + if (predicate.call(thisArg, kValue, k, o)) { + return kValue; + } + k++; + } + return undefined; + } + }); + } + + postbid.que.push(function(conf) { + var content = "\n '; + 'parent.$$PREBID_GLOBAL$$.aolGlobals.pixelsDropped=true;' + formattedPixels + + '}'; } } const bidResponse = bidfactory.createBid(1, bid); - bidResponse.bidderCode = BIDDER_CODE; + bidResponse.bidderCode = bid.bidder; bidResponse.ad = ad; bidResponse.cpm = cpm; bidResponse.width = bidData.w; @@ -234,15 +254,31 @@ const AolAdapter = function AolAdapter() { bidmanager.addBidResponse(bid.placementCode, bidResponse); } + function _isMarketplaceBidder(bidder) { + return bidder === AOL_BIDDERS_CODES.aol || bidder === AOL_BIDDERS_CODES.onedisplay; + } + + function _isNexageBidder(bidder) { + return bidder === AOL_BIDDERS_CODES.aol || bidder === AOL_BIDDERS_CODES.onemobile; + } + function _isNexageRequestPost(bid) { - if (bid.params.id && bid.params.imp && bid.params.imp[0]) { + if (_isNexageBidder(bid.bidder) && bid.params.id && bid.params.imp && bid.params.imp[0]) { let imp = bid.params.imp[0]; return imp.id && imp.tagid && - ((imp.banner && imp.banner.w && imp.banner.h) || - (imp.video && imp.video.mimes && imp.video.minduration && imp.video.maxduration)); + ((imp.banner && imp.banner.w && imp.banner.h) || + (imp.video && imp.video.mimes && imp.video.minduration && imp.video.maxduration)); } } + function _isNexageRequestGet(bid) { + return _isNexageBidder(bid.bidder) && bid.params.dcn && bid.params.pos; + } + + function _isMarketplaceRequest(bid) { + return _isMarketplaceBidder(bid.bidder) && bid.params.placement && bid.params.network; + } + function _callBids(params) { utils._each(params.bids, bid => { let apiUrl; @@ -251,9 +287,10 @@ const AolAdapter = function AolAdapter() { withCredentials: true }; let isNexageRequestPost = _isNexageRequestPost(bid); - if (bid.params.placement && bid.params.network) { - apiUrl = _buildMarketplaceUrl(bid); - } else if(bid.params.dcn && bid.params.pos || isNexageRequestPost) { + let isNexageRequestGet = _isNexageRequestGet(bid); + let isMarketplaceRequest = _isMarketplaceRequest(bid); + + if (isNexageRequestGet || isNexageRequestPost) { apiUrl = _buildNexageApiUrl(bid); if (isNexageRequestPost) { data = bid.params; @@ -263,7 +300,10 @@ const AolAdapter = function AolAdapter() { options.method = 'POST'; options.contentType = 'application/json'; } + } else if (isMarketplaceRequest) { + apiUrl = _buildMarketplaceUrl(bid); } + if (apiUrl) { ajax(apiUrl, response => { // Needs to be here in case bidderSettings are defined after requestBids() is called @@ -279,7 +319,7 @@ const AolAdapter = function AolAdapter() { showCpmAdjustmentWarning = false; // warning is shown at most once if (!response && response.length <= 0) { - utils.logError('Empty bid response', BIDDER_CODE, bid); + utils.logError('Empty bid response', AOL_BIDDERS_CODES.aol, bid); _addErrorBidResponse(bid, response); return; } @@ -287,21 +327,27 @@ const AolAdapter = function AolAdapter() { try { response = JSON.parse(response); } catch (e) { - utils.logError('Invalid JSON in bid response', BIDDER_CODE, bid); + utils.logError('Invalid JSON in bid response', AOL_BIDDERS_CODES.aol, bid); _addErrorBidResponse(bid, response); return; } _addBidResponse(bid, response); - }, data, options); } }); } - return { - callBids: _callBids - }; + return Object.assign(BaseAdapter.createNew(AOL_BIDDERS_CODES.aol), { + callBids: _callBids, + createNew: function () { + return new AolAdapter(); + } + }); }; +adaptermanager.registerBidAdapter(new AolAdapter(), AOL_BIDDERS_CODES.aol); +adaptermanager.aliasBidAdapter(AOL_BIDDERS_CODES.aol, AOL_BIDDERS_CODES.onedisplay); +adaptermanager.aliasBidAdapter(AOL_BIDDERS_CODES.aol, AOL_BIDDERS_CODES.onemobile); + module.exports = AolAdapter; diff --git a/src/adapters/analytics/aolPartnersIds.json b/modules/aolPartnersIds.json similarity index 88% rename from src/adapters/analytics/aolPartnersIds.json rename to modules/aolPartnersIds.json index c215c380e82..d540bad0e42 100644 --- a/src/adapters/analytics/aolPartnersIds.json +++ b/modules/aolPartnersIds.json @@ -72,5 +72,14 @@ "pubgears": 71, "adsupply": 72, "quantcast": 73, - "prebidServer": 74 + "prebidServer": 74, + "onemobile": 75, + "onedisplay": 76, + "adyoulike": 77, + "carambola": 78, + "cox": 79, + "eplanning": 80, + "spotx": 81, + "ucfunnel": 82, + "kargo": 83 } diff --git a/modules/appnexusAnalyticsAdapter.js b/modules/appnexusAnalyticsAdapter.js new file mode 100644 index 00000000000..f9756de23e3 --- /dev/null +++ b/modules/appnexusAnalyticsAdapter.js @@ -0,0 +1,19 @@ +/** + * appnexus.js - AppNexus Prebid Analytics Adapter + */ + +import adapter from 'src/AnalyticsAdapter'; +import adaptermanager from 'src/adaptermanager'; + +var appnexusAdapter = adapter({ + global: 'AppNexusPrebidAnalytics', + handler: 'on', + analyticsType: 'bundle' +}); + +adaptermanager.registerAnalyticsAdapter({ + adapter: appnexusAdapter, + code: 'appnexus' +}); + +export default appnexusAdapter; diff --git a/src/adapters/appnexusAst.js b/modules/appnexusAstBidAdapter.js similarity index 70% rename from src/adapters/appnexusAst.js rename to modules/appnexusAstBidAdapter.js index 3293cc4d5a9..284d8eef10b 100644 --- a/src/adapters/appnexusAst.js +++ b/modules/appnexusAstBidAdapter.js @@ -1,17 +1,29 @@ -import Adapter from 'src/adapters/adapter'; +import Adapter from 'src/adapter'; import { Renderer } from 'src/Renderer'; import bidfactory from 'src/bidfactory'; import bidmanager from 'src/bidmanager'; import * as utils from 'src/utils'; import { ajax } from 'src/ajax'; import { STATUS } from 'src/constants'; +import adaptermanager from 'src/adaptermanager'; -const ENDPOINT = '//ib.adnxs.com/ut/v2/prebid'; +const ENDPOINT = '//ib.adnxs.com/ut/v3/prebid'; +const SUPPORTED_AD_TYPES = ['banner', 'video', 'video-outstream', 'native']; const VIDEO_TARGETING = ['id', 'mimes', 'minduration', 'maxduration', 'startdelay', 'skippable', 'playback_method', 'frameworks']; -const USER_PARAMS = [ - 'age', 'external_uid', 'segments', 'gender', 'dnt', 'language' -]; +const USER_PARAMS = ['age', 'external_uid', 'segments', 'gender', 'dnt', 'language']; +const NATIVE_MAPPING = { + body: 'description', + image: { + serverName: 'main_image', + serverParams: { required: true, sizes: [{}] } + }, + icon: { + serverName: 'icon', + serverParams: { required: true, sizes: [{}] } + }, + sponsoredBy: 'sponsored_by' +}; /** * Bidder adapter for /ut endpoint. Given the list of all ad unit tag IDs, @@ -19,13 +31,14 @@ const USER_PARAMS = [ * to Prebid.js. This adapter supports alias bidding. */ function AppnexusAstAdapter() { - let baseAdapter = Adapter.createNew('appnexusAst'); let bidRequests = {}; let usersync = false; /* Prebid executes this function when the page asks to send out bid requests */ baseAdapter.callBids = function(bidRequest) { + bidRequests = {}; + const bids = bidRequest.bids || []; var member = 0; let userObj; @@ -39,7 +52,7 @@ function AppnexusAstAdapter() { tag.sizes = getSizes(bid.sizes); tag.primary_size = tag.sizes[0]; tag.uuid = bid.bidId; - if(bid.params.placementId) { + if (bid.params.placementId) { tag.id = parseInt(bid.params.placementId, 10); } else { tag.code = bid.params.invCode; @@ -76,7 +89,39 @@ function AppnexusAstAdapter() { tag.keywords = getKeywords(bid.params.keywords); } - if (bid.mediaType === 'video') {tag.require_asset_url = true;} + if (bid.mediaType === 'native') { + tag.ad_types = ['native']; + + if (bid.nativeParams) { + const nativeRequest = {}; + + // map standard prebid native asset identifier to /ut parameters + // e.g., tag specifies `body` but /ut only knows `description` + // mapping may be in form {tag: ''} or + // {tag: {serverName: '', serverParams: {...}}} + Object.keys(bid.nativeParams).forEach(key => { + // check if one of the forms is used, otherwise + // a mapping wasn't specified so pass the key straight through + const requestKey = + (NATIVE_MAPPING[key] && NATIVE_MAPPING[key].serverName) || + NATIVE_MAPPING[key] || + key; + + // if the mapping for this identifier specifies required server + // params via the `serverParams` object, merge that in + const params = Object.assign({}, + bid.nativeParams[key], + NATIVE_MAPPING[key] && NATIVE_MAPPING[key].serverParams + ); + + nativeRequest[requestKey] = params; + }); + + tag.native = {layouts: [nativeRequest]}; + } + } + + if (bid.mediaType === 'video') { tag.require_asset_url = true; } if (bid.params.video) { tag.video = {}; // place any valid video params on the tag @@ -103,7 +148,7 @@ function AppnexusAstAdapter() { const payload = JSON.stringify(payloadJson); ajax(ENDPOINT, handleResponse, payload, { contentType: 'text/plain', - withCredentials : true + withCredentials: true }); } }; @@ -120,7 +165,7 @@ function AppnexusAstAdapter() { if (!parsed || parsed.error) { let errorMessage = `in response for ${baseAdapter.getBidderCode()} adapter`; - if (parsed && parsed.error) {errorMessage += `: ${parsed.error}`;} + if (parsed && parsed.error) { errorMessage += `: ${parsed.error}`; } utils.logError(errorMessage); // signal this response is complete @@ -138,22 +183,26 @@ function AppnexusAstAdapter() { const type = ad && ad.ad_type; let status; - if (cpm !== 0 && (type === 'banner' || type === 'video' || type === 'video-outstream')) { + if (cpm !== 0 && (SUPPORTED_AD_TYPES.includes(type))) { status = STATUS.GOOD; } else { status = STATUS.NO_BID; } - if (type && (type !== 'banner' && type !== 'video' && type !== 'video-outstream')) { + if (type && (!SUPPORTED_AD_TYPES.includes(type))) { utils.logError(`${type} ad type not supported`); } - tag.bidId = tag.uuid; // bidfactory looks for bidId on requested bid + tag.bidId = tag.uuid; // bidfactory looks for bidId on requested bid const bid = createBid(status, tag); + if (type === 'native') bid.mediaType = 'native'; if (type === 'video') bid.mediaType = 'video'; - if (type === 'video-outstream') bid.mediaType = 'video-outstream'; - const placement = bidRequests[bid.adId].placementCode; - bidmanager.addBidResponse(placement, bid); + if (ad && ad.renderer_url) bid.mediaType = 'video-outstream'; + + if (bid.adId in bidRequests) { + const placement = bidRequests[bid.adId].placementCode; + bidmanager.addBidResponse(placement, bid); + } }); if (!usersync) { @@ -186,13 +235,12 @@ function AppnexusAstAdapter() { let values = []; utils._each(v, (val) => { val = utils.getValueString('keywords.' + k, val); - if (val) {values.push(val);} + if (val) { values.push(val); } }); v = values; } else { v = utils.getValueString('keywords.' + k, v); - if (utils.isStr(v)) {v = [v];} - else {return;} // unsuported types - don't send a key + if (utils.isStr(v)) { v = [v]; } else { return; } // unsuported types - don't send a key } arrs.push({key: k, value: v}); }); @@ -228,18 +276,17 @@ function AppnexusAstAdapter() { } function outstreamRender(bid) { - window.ANOutstreamVideo.renderAd({ - tagId: bid.adResponse.tag_id, - sizes: [bid.getSize().split('x')], - targetId: bid.adUnitCode, // target div id to render video - uuid: bid.adResponse.uuid, - adResponse: bid.adResponse, - rendererOptions: bid.renderer.getConfig() - }, handleOutstreamRendererEvents.bind(bid)); - } - - function onOutstreamRendererLoaded() { - // setup code for renderer, if any + // push to render queue because ANOutstreamVideo may not be loaded yet + bid.renderer.push(() => { + window.ANOutstreamVideo.renderAd({ + tagId: bid.adResponse.tag_id, + sizes: [bid.getSize().split('x')], + targetId: bid.adUnitCode, // target div id to render video + uuid: bid.adResponse.uuid, + adResponse: bid.adResponse, + rendererOptions: bid.renderer.getConfig() + }, handleOutstreamRendererEvents.bind(bid)); + }); } function handleOutstreamRendererEvents(id, eventName) { @@ -265,7 +312,6 @@ function AppnexusAstAdapter() { bid.vastUrl = ad.rtb.video.asset_url; bid.descriptionUrl = ad.rtb.video.asset_url; if (ad.renderer_url) { - // outstream video bid.adResponse = tag; @@ -273,9 +319,8 @@ function AppnexusAstAdapter() { id: ad.renderer_id, url: ad.renderer_url, config: { adText: `AppNexus Outstream Video Ad via Prebid.js` }, - callback: () => onOutstreamRendererLoaded.call(null, bid) + loaded: false, }); - try { bid.renderer.setRender(outstreamRender); } catch (err) { @@ -294,6 +339,17 @@ function AppnexusAstAdapter() { bid.adResponse.ad = bid.adResponse.ads[0]; bid.adResponse.ad.video = bid.adResponse.ad.rtb.video; } + } else if (ad.rtb.native) { + const native = ad.rtb.native; + bid.native = { + title: native.title, + body: native.desc, + sponsoredBy: native.sponsored, + image: native.main_img && native.main_img.url, + icon: native.icon && native.icon.url, + clickUrl: native.link.url, + impressionTrackers: native.impression_trackers, + }; } else { bid.width = ad.rtb.banner.width; bid.height = ad.rtb.banner.height; @@ -316,11 +372,14 @@ function AppnexusAstAdapter() { callBids: baseAdapter.callBids, setBidderCode: baseAdapter.setBidderCode, }; - } AppnexusAstAdapter.createNew = function() { return new AppnexusAstAdapter(); }; +adaptermanager.registerBidAdapter(new AppnexusAstAdapter(), 'appnexusAst', { + supportedMediaTypes: ['video', 'native'] +}); + module.exports = AppnexusAstAdapter; diff --git a/src/adapters/appnexus.js b/modules/appnexusBidAdapter.js similarity index 72% rename from src/adapters/appnexus.js rename to modules/appnexusBidAdapter.js index 4dc1a368cbc..a20b7f29e47 100644 --- a/src/adapters/appnexus.js +++ b/modules/appnexusBidAdapter.js @@ -1,11 +1,12 @@ -import { getBidRequest } from '../utils.js'; +import { getBidRequest } from 'src/utils'; +import adaptermanager from 'src/adaptermanager'; -var CONSTANTS = require('../constants.json'); -var utils = require('../utils.js'); -var adloader = require('../adloader.js'); -var bidmanager = require('../bidmanager.js'); -var bidfactory = require('../bidfactory.js'); -var Adapter = require('./adapter.js'); +var CONSTANTS = require('src/constants'); +var utils = require('src/utils'); +var adloader = require('src/adloader'); +var bidmanager = require('src/bidmanager'); +var bidfactory = require('src/bidfactory'); +var Adapter = require('src/adapter'); var AppNexusAdapter; AppNexusAdapter = function AppNexusAdapter() { @@ -13,41 +14,37 @@ AppNexusAdapter = function AppNexusAdapter() { var usersync = false; baseAdapter.callBids = function (params) { - //var bidCode = baseAdapter.getBidderCode(); + // var bidCode = baseAdapter.getBidderCode(); var anArr = params.bids; - //var bidsCount = anArr.length; + // var bidsCount = anArr.length; - //set expected bids count for callback execution - //bidmanager.setExpectedBidsCount(bidCode, bidsCount); + // set expected bids count for callback execution + // bidmanager.setExpectedBidsCount(bidCode, bidsCount); for (var i = 0; i < anArr.length; i++) { var bidRequest = anArr[i]; var callbackId = bidRequest.bidId; adloader.loadScript(buildJPTCall(bidRequest, callbackId)); - //store a reference to the bidRequest from the callback id - //bidmanager.pbCallbackMap[callbackId] = bidRequest; + // store a reference to the bidRequest from the callback id + // bidmanager.pbCallbackMap[callbackId] = bidRequest; } }; function buildJPTCall(bid, callbackId) { - - //determine tag params + // determine tag params var placementId = utils.getBidIdParameter('placementId', bid.params); - //memberId will be deprecated, use member instead + // memberId will be deprecated, use member instead var memberId = utils.getBidIdParameter('memberId', bid.params); var member = utils.getBidIdParameter('member', bid.params); var inventoryCode = utils.getBidIdParameter('invCode', bid.params); var query = utils.getBidIdParameter('query', bid.params); var referrer = utils.getBidIdParameter('referrer', bid.params); var altReferrer = utils.getBidIdParameter('alt_referrer', bid.params); - - //build our base tag, based on if we are http or https - - var jptCall = 'http' + (document.location.protocol === 'https:' ? 's://secure.adnxs.com/jpt?' : '://ib.adnxs.com/jpt?'); + var jptCall = '//ib.adnxs.com/jpt?'; jptCall = utils.tryAppendQueryString(jptCall, 'callback', '$$PREBID_GLOBAL$$.handleAnCB'); jptCall = utils.tryAppendQueryString(jptCall, 'callback_uid', callbackId); @@ -63,23 +60,23 @@ AppNexusAdapter = function AppNexusAdapter() { jptCall = utils.tryAppendQueryString(jptCall, 'code', inventoryCode); jptCall = utils.tryAppendQueryString(jptCall, 'traffic_source_code', (utils.getBidIdParameter('trafficSourceCode', bid.params))); - //sizes takes a bit more logic + // sizes takes a bit more logic var sizeQueryString = ''; var parsedSizes = utils.parseSizesInput(bid.sizes); - //combine string into proper querystring for impbus + // combine string into proper querystring for impbus var parsedSizesLength = parsedSizes.length; if (parsedSizesLength > 0) { - //first value should be "size" + // first value should be "size" sizeQueryString = 'size=' + parsedSizes[0]; if (parsedSizesLength > 1) { - //any subsequent values should be "promo_sizes" + // any subsequent values should be "promo_sizes" sizeQueryString += '&promo_sizes='; for (var j = 1; j < parsedSizesLength; j++) { sizeQueryString += parsedSizes[j] += ','; } - //remove trailing comma + // remove trailing comma if (sizeQueryString && sizeQueryString.charAt(sizeQueryString.length - 1) === ',') { sizeQueryString = sizeQueryString.slice(0, sizeQueryString.length - 1); } @@ -90,18 +87,18 @@ AppNexusAdapter = function AppNexusAdapter() { jptCall += sizeQueryString + '&'; } - //this will be deprecated soon + // this will be deprecated soon var targetingParams = utils.parseQueryStringParameters(query); if (targetingParams) { - //don't append a & here, we have already done it in parseQueryStringParameters + // don't append a & here, we have already done it in parseQueryStringParameters jptCall += targetingParams; } - //append custom attributes: + // append custom attributes: var paramsCopy = Object.assign({}, bid.params); - //delete attributes already used + // delete attributes already used delete paramsCopy.placementId; delete paramsCopy.memberId; delete paramsCopy.invCode; @@ -110,15 +107,15 @@ AppNexusAdapter = function AppNexusAdapter() { delete paramsCopy.alt_referrer; delete paramsCopy.member; - //get the reminder + // get the reminder var queryParams = utils.parseQueryStringParameters(paramsCopy); - //append + // append if (queryParams) { jptCall += queryParams; } - //append referrer + // append referrer if (referrer === '') { referrer = utils.getTopWindowUrl(); } @@ -126,7 +123,7 @@ AppNexusAdapter = function AppNexusAdapter() { jptCall = utils.tryAppendQueryString(jptCall, 'referrer', referrer); jptCall = utils.tryAppendQueryString(jptCall, 'alt_referrer', altReferrer); - //remove the trailing "&" + // remove the trailing "&" if (jptCall.lastIndexOf('&') === jptCall.length - 1) { jptCall = jptCall.substring(0, jptCall.length - 1); } @@ -136,31 +133,27 @@ AppNexusAdapter = function AppNexusAdapter() { // @endif - //append a timer here to track latency + // append a timer here to track latency bid.startTime = new Date().getTime(); return jptCall; - } - //expose the callback to the global object: + // expose the callback to the global object: $$PREBID_GLOBAL$$.handleAnCB = function (jptResponseObj) { - var bidCode; if (jptResponseObj && jptResponseObj.callback_uid) { - var responseCPM; var id = jptResponseObj.callback_uid; var placementCode = ''; var bidObj = getBidRequest(id); if (bidObj) { - bidCode = bidObj.bidder; placementCode = bidObj.placementCode; - //set the status + // set the status bidObj.status = CONSTANTS.STATUS.GOOD; } @@ -172,13 +165,13 @@ AppNexusAdapter = function AppNexusAdapter() { if (jptResponseObj.result && jptResponseObj.result.cpm && jptResponseObj.result.cpm !== 0) { responseCPM = parseInt(jptResponseObj.result.cpm, 10); - //CPM response from /jpt is dollar/cent multiplied by 10000 - //in order to avoid using floats - //switch CPM to "dollar/cent" + // CPM response from /jpt is dollar/cent multiplied by 10000 + // in order to avoid using floats + // switch CPM to "dollar/cent" responseCPM = responseCPM / 10000; - //store bid response - //bid status is good (indicating 1) + // store bid response + // bid status is good (indicating 1) var adId = jptResponseObj.result.creative_id; bid = bidfactory.createBid(1, bidObj); bid.creative_id = adId; @@ -190,14 +183,13 @@ AppNexusAdapter = function AppNexusAdapter() { bid.dealId = jptResponseObj.result.deal_id; bidmanager.addBidResponse(placementCode, bid); - } else { - //no response data + // no response data // @if NODE_ENV='debug' utils.logMessage('No prebid response from AppNexus for placement code ' + placementCode); // @endif - //indicate that there is no bid for this placement + // indicate that there is no bid for this placement bid = bidfactory.createBid(2, bidObj); bid.bidderCode = bidCode; bidmanager.addBidResponse(placementCode, bid); @@ -213,17 +205,13 @@ AppNexusAdapter = function AppNexusAdapter() { } usersync = true; } - - } else { - //no response data + // no response data // @if NODE_ENV='debug' utils.logMessage('No prebid response for placement %%PLACEMENT%%'); // @endif - } - }; return { @@ -238,4 +226,13 @@ AppNexusAdapter.createNew = function () { return new AppNexusAdapter(); }; +adaptermanager.registerBidAdapter(new AppNexusAdapter(), 'appnexus'); +adaptermanager.aliasBidAdapter('appnexus', 'brealtime'); +adaptermanager.aliasBidAdapter('appnexus', 'pagescience'); +adaptermanager.aliasBidAdapter('appnexus', 'defymedia'); +adaptermanager.aliasBidAdapter('appnexus', 'gourmetads'); +adaptermanager.aliasBidAdapter('appnexus', 'matomy'); +adaptermanager.aliasBidAdapter('appnexus', 'featureforward'); +adaptermanager.aliasBidAdapter('appnexus', 'oftmedia'); + module.exports = AppNexusAdapter; diff --git a/src/adapters/atomx.js b/modules/atomxBidAdapter.js similarity index 85% rename from src/adapters/atomx.js rename to modules/atomxBidAdapter.js index 4935382123a..5b8652561eb 100644 --- a/src/adapters/atomx.js +++ b/modules/atomxBidAdapter.js @@ -1,9 +1,10 @@ -var CONSTANTS = require('../constants.json'); -var bidfactory = require('../bidfactory.js'); -var bidmanager = require('../bidmanager.js'); +var CONSTANTS = require('src/constants.json'); +var bidfactory = require('src/bidfactory.js'); +var bidmanager = require('src/bidmanager.js'); var adloader = require('src/adloader.js'); -var Ajax = require('../ajax'); -var utils = require('../utils.js'); +var Ajax = require('src/ajax'); +var utils = require('src/utils.js'); +var adaptermanager = require('src/adaptermanager'); /** * Adapter for requesting bids from Atomx. @@ -72,4 +73,7 @@ var AtomxAdapter = function AtomxAdapter() { }; }; + +adaptermanager.registerBidAdapter(new AtomxAdapter(), 'atomx'); + module.exports = AtomxAdapter; diff --git a/modules/audienceNetworkBidAdapter.js b/modules/audienceNetworkBidAdapter.js new file mode 100644 index 00000000000..0a67020b86d --- /dev/null +++ b/modules/audienceNetworkBidAdapter.js @@ -0,0 +1,251 @@ +/** + * @file AudienceNetwork adapter. + */ +import { ajax } from 'src/ajax'; +import { createBid } from 'src/bidfactory'; +import { addBidResponse } from 'src/bidmanager'; +import { STATUS } from 'src/constants.json'; +import { format } from 'src/url'; +import { logError } from 'src/utils'; +import { createNew } from 'src/adapter'; +import adaptermanager from 'src/adaptermanager'; + +const { setBidderCode, getBidderCode } = createNew('audienceNetwork'); + +/** + * Does this bid request contain valid parameters? + * @param {Object} bid + * @returns {Boolean} + */ +const validateBidRequest = bid => + typeof bid.params === 'object' && + typeof bid.params.placementId === 'string' && + bid.params.placementId.length > 0 && + Array.isArray(bid.sizes) && bid.sizes.length > 0 && + (isVideo(bid.params.format) || bid.sizes.map(flattenSize).some(isValidSize)); + +/** + * Flattens a 2-element [W, H] array as a 'WxH' string, + * otherwise passes value through. + * @param {Array|String} size + * @returns {String} + */ +const flattenSize = size => + (Array.isArray(size) && size.length === 2) ? `${size[0]}x${size[1]}` : size; + +/** + * Expands a 'WxH' string as a 2-element [W, H] array + * @param {String} size + * @returns {Array} + */ +const expandSize = size => size.split('x').map(Number); + +/** + * Is this a valid slot size? + * @param {String} size + * @returns {Boolean} + */ +const isValidSize = size => ['300x250', '320x50'].includes(size); + +/** + * Is this a video format? + * @param {String} format + * @returns {Boolean} + */ +const isVideo = format => format === 'video'; + +/** + * Which SDK version should be used for this format? + * @param {String} format + * @returns {String} + */ +const sdkVersion = format => isVideo(format) ? '' : '5.5.web'; + +/** + * Does the search part of the URL contain "anhb_testmode" + * and therefore indicate testmode should be used? + * @returns {String} "true" or "false" + */ +const isTestmode = () => Boolean( + window && window.location && + typeof window.location.search === 'string' && + window.location.search.indexOf('anhb_testmode') !== -1 +).toString(); + +/** + * Parse JSON-as-string into an Object, default to empty. + * @param {String} JSON-as-string + * @returns {Object} + */ +const parseJson = jsonAsString => { + let data = {}; + try { + data = JSON.parse(jsonAsString); + } catch (err) {} + return data; +}; + +/** + * Generate ad HTML for injection into an iframe + * @param {String} placementId + * @param {String} format + * @param {String} bidId + * @returns {String} HTML + */ +const createAdHtml = (placementId, format, bidId) => { + const nativeStyle = format === 'native' ? '' : ''; + const nativeContainer = format === 'native' ? '
' : ''; + return `${nativeStyle}
+ +${nativeContainer}
`; +}; + +/** + * Creates a "good" Bid object with the given bid ID and CPM. + * @param {String} placementId + * @param {String} size + * @param {String} format + * @param {String} bidId + * @param {Number} cpmCents + * @param {String} pageurl + * @returns {Object} Bid + */ +const createSuccessBidResponse = (placementId, size, format, bidId, cpmCents, pageurl) => { + const bid = createBid(STATUS.GOOD, { bidId }); + // Prebid attributes + bid.bidderCode = getBidderCode(); + bid.cpm = cpmCents / 100; + bid.ad = createAdHtml(placementId, format, bidId); + [bid.width, bid.height] = expandSize(size); + + // Audience Network attributes + bid.hb_bidder = 'fan'; + bid.fb_bidid = bidId; + bid.fb_format = format; + bid.fb_placementid = placementId; + // Video attributes + if (isVideo(format)) { + const vast = `https://an.facebook.com/v1/instream/vast.xml?placementid=${placementId}&pageurl=${encodeURIComponent(pageurl)}&playerwidth=${bid.width}&playerheight=${bid.height}&bidid=${bidId}`; + bid.mediaType = 'video'; + bid.vastUrl = vast; + bid.descriptionUrl = vast; + } + return bid; +}; + +/** + * Creates a "no bid" Bid object. + * @returns {Object} Bid + */ +const createFailureBidResponse = () => { + const bid = createBid(STATUS.NO_BID); + bid.bidderCode = getBidderCode(); + return bid; +}; + +/** + * Fetch bids for given parameters. + * @param {Object} bidRequest + * @param {Array} params.bids - list of bids + * @param {String} params.bids[].placementCode - Prebid placement identifier + * @param {Object} params.bids[].params + * @param {String} params.bids[].params.placementId - Audience Network placement identifier + * @param {String} params.bids[].params.format - Optional format, one of 'video', 'native' or 'fullwidth' if set + * @param {Array} params.bids[].sizes - list of desired advert sizes + * @param {Array} params.bids[].sizes[] - Size arrays [h,w]: should include one of [300, 250], [320, 50]: first matched size is used + * @returns {void} + */ +const callBids = bidRequest => { + // Build lists of adUnitCodes, placementids, adformats and sizes + const adUnitCodes = []; + const placementids = []; + const adformats = []; + const sizes = []; + const sdk = []; + + bidRequest.bids + .filter(validateBidRequest) + .forEach(bid => bid.sizes + .map(flattenSize) + .filter(size => isValidSize(size) || isVideo(bid.params.format)) + .slice(0, 1) + .forEach(size => { + adUnitCodes.push(bid.placementCode); + placementids.push(bid.params.placementId); + adformats.push(bid.params.format || size); + sizes.push(size); + sdk.push(sdkVersion(bid.params.format)); + }) + ); + + if (placementids.length) { + // Build URL + const testmode = isTestmode(); + const pageurl = location.href; + const search = { + placementids, + adformats, + testmode, + pageurl, + sdk + }; + const video = adformats.findIndex(isVideo); + if (video !== -1) { + [search.playerwidth, search.playerheight] = expandSize(sizes[video]); + } + const url = format({ + protocol: 'https', + host: 'an.facebook.com', + pathname: '/v2/placementbid.json', + search + }); + // Request + ajax(url, res => { + // Handle response + const data = parseJson(res); + if (data.errors && data.errors.length) { + const noBid = createFailureBidResponse(); + adUnitCodes.forEach(adUnitCode => addBidResponse(adUnitCode, noBid)); + data.errors.forEach(logError); + } else { + // For each placementId in bids Object + Object.keys(data.bids) + // extract Array of bid responses + .map(placementId => data.bids[placementId]) + // flatten + .reduce((a, b) => a.concat(b), []) + // call addBidResponse + .forEach((bid, i) => + addBidResponse(adUnitCodes[i], createSuccessBidResponse( + bid.placement_id, + sizes[i], + adformats[i], + bid.bid_id, + bid.bid_price_cents, + pageurl + )) + ); + } + }, null, { withCredentials: true }); + } else { + // No valid bids + logError('No valid bids requested'); + } +}; + +/** + * @class AudienceNetwork + * @type {Object} + * @property {Function} callBids - fetch bids for given parameters + * @property {Function} setBidderCode - used for bidder aliasing + * @property {Function} getBidderCode - unique 'audienceNetwork' identifier + */ +const AudienceNetwork = () => ({ callBids, setBidderCode, getBidderCode }); + +adaptermanager.registerBidAdapter(new AudienceNetwork(), 'audienceNetwork', { + supportedMediaTypes: ['video'] +}); + +module.exports = AudienceNetwork; diff --git a/src/adapters/beachfront.js b/modules/beachfrontBidAdapter.js similarity index 88% rename from src/adapters/beachfront.js rename to modules/beachfrontBidAdapter.js index b10eb00517e..29434a35c0c 100644 --- a/src/adapters/beachfront.js +++ b/modules/beachfrontBidAdapter.js @@ -1,9 +1,10 @@ -import Adapter from 'src/adapters/adapter'; +import Adapter from 'src/adapter'; import bidfactory from 'src/bidfactory'; import bidmanager from 'src/bidmanager'; import * as utils from 'src/utils'; import { ajax } from 'src/ajax'; import { STATUS } from 'src/constants'; +import adaptermanager from 'src/adaptermanager'; const ENDPOINT = '//reachms.bfmio.com/bid.json?exchange_id='; @@ -16,7 +17,7 @@ function BeachfrontAdapter() { var bidRequest = getBidRequest(bid); var RTBDataParams = prepareAndSaveRTBRequestParams(bid); if (!RTBDataParams) { - var error = "No bid params"; + var error = 'No bid params'; utils.logError(error); if (bid && bid.placementCode) { bidmanager.addBidResponse(bid.placementCode, createBid(bid, STATUS.NO_BID)); @@ -29,7 +30,6 @@ function BeachfrontAdapter() { withCredentials: true }); }); - }; function getBidRequest(bid) { @@ -52,22 +52,25 @@ function BeachfrontAdapter() { return ((/(ios|ipod|ipad|iphone|android)/i).test(global.navigator.userAgent) ? 1 : ((/(smart[-]?tv|hbbtv|appletv|googletv|hdmi|netcast\.tv|viera|nettv|roku|\bdtv\b|sonydtv|inettvbrowser|\btv\b)/i).test(global.navigator.userAgent) ? 1 : 2)); } - var bidRequestObject = { + var bidRequestObject = { isPrebid: true, appId: bid.params.appId, domain: document.location.hostname, - imp:[{ - video:{}, + imp: [{ + video: { + w: bid.width, + h: bid.height + }, bidfloor: bid.params.bidfloor }], - site:{ + site: { page: utils.getTopWindowLocation().host }, - device:{ + device: { ua: navigator.userAgent, devicetype: fetchDeviceType() }, - cur:["USD"] + cur: ['USD'] }; return bidRequestObject; } @@ -83,11 +86,11 @@ function BeachfrontAdapter() { utils.logError(error); } } else { - utils.logWarn("No bid response"); + utils.logWarn('No bid response'); } if (!parsed || parsed.error || !parsed.url || !parsed.bidPrice) { - utils.logWarn("No Valid Bid"); + utils.logWarn('No Valid Bid'); bidmanager.addBidResponse(bidRequest.placementCode, createBid(bidRequest, STATUS.NO_BID)); return; } @@ -130,4 +133,8 @@ BeachfrontAdapter.createNew = function () { return new BeachfrontAdapter(); }; +adaptermanager.registerBidAdapter(new BeachfrontAdapter(), 'beachfront', { + supportedMediaTypes: ['video'] +}); + module.exports = BeachfrontAdapter; diff --git a/src/adapters/bidfluence.js b/modules/bidfluenceBidAdapter.js similarity index 79% rename from src/adapters/bidfluence.js rename to modules/bidfluenceBidAdapter.js index bd3790e8652..73b548a4993 100644 --- a/src/adapters/bidfluence.js +++ b/modules/bidfluenceBidAdapter.js @@ -1,57 +1,58 @@ -const bidmanager = require('../bidmanager.js'); -const bidfactory = require('../bidfactory.js'); -const utils = require('../utils.js'); -const adloader = require('../adloader'); - -var BidfluenceAdapter = function BidfluenceAdapter() { - - const scriptUrl = "//cdn.bidfluence.com/forge.js"; - - $$PREBID_GLOBAL$$.bfPbjsCB = function (bfr) { - var bidRequest = utils.getBidRequest(bfr.cbID); - var bidObject = null; - if (bfr.cpm > 0) { - bidObject = bidfactory.createBid(1, bidRequest); - bidObject.bidderCode = 'bidfluence'; - bidObject.cpm = bfr.cpm; - bidObject.ad = bfr.ad; - bidObject.width = bfr.width; - bidObject.height = bfr.height; - } else { - bidObject = bidfactory.createBid(2, bidRequest); - bidObject.bidderCode = 'bidfluence'; - } - - bidmanager.addBidResponse(bfr.placementCode, bidObject); - }; - - function _callBids(params) { - var bfbids = params.bids || []; - for (var i = 0; i < bfbids.length; i++) { - var bid = bfbids[i]; - call(bid); - } - } - function call(bid) { - - var adunitId = utils.getBidIdParameter('adunitId', bid.params); - var publisherId = utils.getBidIdParameter('pubId', bid.params); - var reservePrice = utils.getBidIdParameter('reservePrice', bid.params); - var pbjsBfobj = { - placementCode: bid.placementCode, - cbID: bid.bidId - }; - - var cb = function () { - /* globals FORGE */ - FORGE.init([adunitId, publisherId, pbjsBfobj, reservePrice]); - }; - - adloader.loadScript(scriptUrl, cb); - } - return { - callBids: _callBids - }; -}; - -module.exports = BidfluenceAdapter; +const bidmanager = require('src/bidmanager'); +const bidfactory = require('src/bidfactory'); +const utils = require('src/utils'); +const adloader = require('src/adloader'); +const adaptermanager = require('src/adaptermanager'); + +var BidfluenceAdapter = function BidfluenceAdapter() { + const scriptUrl = '//cdn.bidfluence.com/forge.js'; + + $$PREBID_GLOBAL$$.bfPbjsCB = function (bfr) { + var bidRequest = utils.getBidRequest(bfr.cbID); + var bidObject = null; + if (bfr.cpm > 0) { + bidObject = bidfactory.createBid(1, bidRequest); + bidObject.bidderCode = 'bidfluence'; + bidObject.cpm = bfr.cpm; + bidObject.ad = bfr.ad; + bidObject.width = bfr.width; + bidObject.height = bfr.height; + } else { + bidObject = bidfactory.createBid(2, bidRequest); + bidObject.bidderCode = 'bidfluence'; + } + + bidmanager.addBidResponse(bfr.placementCode, bidObject); + }; + + function _callBids(params) { + var bfbids = params.bids || []; + for (var i = 0; i < bfbids.length; i++) { + var bid = bfbids[i]; + call(bid); + } + } + function call(bid) { + var adunitId = utils.getBidIdParameter('adunitId', bid.params); + var publisherId = utils.getBidIdParameter('pubId', bid.params); + var reservePrice = utils.getBidIdParameter('reservePrice', bid.params); + var pbjsBfobj = { + placementCode: bid.placementCode, + cbID: bid.bidId + }; + + var cb = function () { + /* globals FORGE */ + FORGE.init([adunitId, publisherId, pbjsBfobj, reservePrice]); + }; + + adloader.loadScript(scriptUrl, cb); + } + return { + callBids: _callBids + }; +}; + +adaptermanager.registerBidAdapter(new BidfluenceAdapter(), 'bidfluence'); + +module.exports = BidfluenceAdapter; diff --git a/src/adapters/brightcom.js b/modules/brightcomBidAdapter.js similarity index 90% rename from src/adapters/brightcom.js rename to modules/brightcomBidAdapter.js index 9df4a872d47..c8945e58f91 100644 --- a/src/adapters/brightcom.js +++ b/modules/brightcomBidAdapter.js @@ -1,14 +1,14 @@ -var CONSTANTS = require('../constants.json'); -var utils = require('../utils.js'); -var bidfactory = require('../bidfactory.js'); -var bidmanager = require('../bidmanager.js'); -var adloader = require('../adloader'); +var CONSTANTS = require('src/constants.json'); +var utils = require('src/utils.js'); +var bidfactory = require('src/bidfactory.js'); +var bidmanager = require('src/bidmanager.js'); +var adloader = require('src/adloader'); +var adaptermanager = require('src/adaptermanager'); /** * Adapter for requesting bids from Brightcom */ var BrightcomAdapter = function BrightcomAdapter() { - // Set Brightcom Bidder URL var brightcomUrl = 'hb.iselephant.com/auc/ortb'; @@ -20,10 +20,9 @@ var BrightcomAdapter = function BrightcomAdapter() { // Manage the requested and received ad units' codes, to know which are invalid (didn't return) var reqAdUnitsCode = [], - resAdUnitsCode = []; + resAdUnitsCode = []; function _callBids(params) { - var bidRequests = params.bids || []; // Get page data @@ -38,12 +37,11 @@ var BrightcomAdapter = function BrightcomAdapter() { // Go through the requests and build array of impressions utils._each(bidRequests, function(bid) { - // Get impression details var tagId = utils.getBidIdParameter('tagId', bid.params); var ref = utils.getBidIdParameter('ref', bid.params); - var adWidth=0; - var adHeight=0; + var adWidth = 0; + var adHeight = 0; // If no publisher id is set, use the current if (pubId === '') { @@ -83,18 +81,17 @@ var BrightcomAdapter = function BrightcomAdapter() { // Add current impression to collection brightcomImps.push(imp); // Add mapping to current bid via impression id - //bidmanager.pbCallbackMap[imp.id] = bid; + // bidmanager.pbCallbackMap[imp.id] = bid; // Add current ad unit's code to tracking reqAdUnitsCode.push(bid.placementCode); - }); // Build the bid request var brightcomBidReq = { id: utils.getUniqueIdentifierStr(), imp: brightcomImps, - site:{ + site: { publisher: { id: pubId }, @@ -119,27 +116,23 @@ var BrightcomAdapter = function BrightcomAdapter() { adloader.loadScript(bidRequestCallUrl); } - //expose the callback to the global object: + // expose the callback to the global object: $$PREBID_GLOBAL$$.brightcomResponse = function(brightcomResponseObj) { - var bid = {}; // Make sure response is valid if ( - (brightcomResponseObj) && (brightcomResponseObj.id) && + (brightcomResponseObj) && (brightcomResponseObj.id) && (brightcomResponseObj.seatbid) && (brightcomResponseObj.seatbid.length !== 0) && (brightcomResponseObj.seatbid[0].bid) && (brightcomResponseObj.seatbid[0].bid.length !== 0) ) { - // Go through the received bids - brightcomResponseObj.seatbid[0].bid.forEach( function(curBid) { - + brightcomResponseObj.seatbid[0].bid.forEach(function(curBid) { // Get the bid request data var bidRequest = $$PREBID_GLOBAL$$._bidsRequested.find(bidSet => bidSet.bidderCode === 'brightcom').bids[0]; // this assumes a single request only // Make sure the bid exists if (bidRequest) { - var placementCode = bidRequest.placementCode; bidRequest.status = CONSTANTS.STATUS.GOOD; @@ -185,10 +178,8 @@ var BrightcomAdapter = function BrightcomAdapter() { // Add current ad unit's code to tracking resAdUnitsCode.push(placementCode); - } }); - } // Define all unreceived ad unit codes as invalid (if Brightcom don't want to bid on an impression, it won't include it in the response) @@ -202,7 +193,6 @@ var BrightcomAdapter = function BrightcomAdapter() { bidmanager.addBidResponse(adUnitCode, bid); } } - }; return { @@ -210,4 +200,6 @@ var BrightcomAdapter = function BrightcomAdapter() { }; }; +adaptermanager.registerBidAdapter(new BrightcomAdapter(), 'brightcom'); + module.exports = BrightcomAdapter; diff --git a/modules/carambolaBidAdapter.js b/modules/carambolaBidAdapter.js new file mode 100644 index 00000000000..3c65e7da77e --- /dev/null +++ b/modules/carambolaBidAdapter.js @@ -0,0 +1,196 @@ +/** + * Carambola adapter + */ + +const bidfactory = require('src/bidfactory.js'); +const bidmanager = require('src/bidmanager.js'); +const utils = require('src/utils.js'); +const ajax = require('src/ajax.js').ajax; +const adaptermanager = require('src/adaptermanager'); + +function CarambolaAdapter() { + const BIDDER_CODE = 'carambola'; + const REQUEST_PATH = 'hb/inimage/getHbBIdProcessedResponse'; + + function _addErrorBidResponse(bid, response = {}, errorMsg = '') { + const bidResponse = bidfactory.createBid(2, bid); + bidResponse.bidderCode = BIDDER_CODE; + bidResponse.reason = errorMsg; + bidmanager.addBidResponse(_getCustomAdUnitCode(bid), bidResponse); + } + // looking at the utils.js at getBidderRequest method. this is what is requested. + function _getCustomAdUnitCode(bid) { + return bid.placementCode; + } + + function _addBidResponse(bid, response) { + const bidResponse = bidfactory.createBid(1, bid); + bidResponse.bidderCode = BIDDER_CODE; + bidResponse.ad = response.ad; + bidResponse.cpm = response.cpm; + bidResponse.width = response.width; + bidResponse.height = response.height; + bidResponse.currencyCode = response.cur; + bidResponse.token = response.token; + bidResponse.pvid = response.pageViewId; + + bidmanager.addBidResponse(_getCustomAdUnitCode(bid), bidResponse); + } + + function _getPageViewId() { + window.Cbola = window.Cbola || {}; + window.Cbola.HB = window.Cbola.HB || {}; + window.Cbola.HB.pvid = window.Cbola.HB.pvid || _createPageViewId(); + return window.Cbola.HB.pvid; + } + + function _createPageViewId() { + function _pad(number) { + return number > 9 ? number : '0' + number + } + + const MIN = 10000; + const MAX = 90000; + let now = new Date(); + + var pvid = + _pad(now.getDate()) + + _pad(now.getMonth() + 1) + + _pad(now.getFullYear() % 100) + + _pad(now.getHours()) + + _pad(now.getMinutes()) + + _pad(now.getSeconds()) + + _pad(now.getMilliseconds() % 100) + + Math.floor((Math.random() * MAX) + MIN); + + return pvid; + } + + // sends a request for each bid + function _buildRequest(bids, params) { + if (!utils.isArray(bids)) { + return; + } + // iterate on every bid and return the response to the hb manager + utils._each(bids, bid => { + let tempParams = params || {}; + tempParams.cbolaMode = bid.params.cbolaMode || 0; + tempParams.wid = bid.params.wid || 0; + tempParams.pixel = bid.params.pixel || ''; + tempParams.bidFloor = bid.params.bidFloor || 0; + tempParams.pageViewId = _getPageViewId(); + tempParams.hb_token = utils.generateUUID(); + tempParams.sizes = utils.parseSizesInput(bid.sizes) + ''; + tempParams.bidsCount = bids.length; + + for (let customParam in bid.params.customParams) { + if (bid.params.customParams.hasOwnProperty(customParam)) { + tempParams['c_' + customParam] = bid.params.customParams[customParam]; + } + } + + let server = bid.params.server || 'route.carambo.la'; + let cbolaHbApiUrl = '//' + server + '/' + REQUEST_PATH; + + // the responses of the bid requests + ajax(cbolaHbApiUrl + _jsonToQueryString(tempParams), response => { + // no response + if (!response || response.cpm <= 0) { + utils.logError('Empty bid response', BIDDER_CODE, bid); + _addErrorBidResponse(bid, response, 'Empty bid response'); + return; + } + try { + response = JSON.parse(response); + if (response && response.cpm <= 0) + { + utils.logError('Bid response returned 0', BIDDER_CODE, bid); + _addErrorBidResponse(bid, response, 'Bid response returned 0'); + return; + } + } catch (e) { + utils.logError('Invalid JSON in bid response', BIDDER_CODE, bid); + _addErrorBidResponse(bid, response, 'Invalid JSON in bid response'); + return; + } + _addBidResponse(bid, response); + }, null, {method: 'GET'}); + }); + } + + // build the genral request to the server + function _callBids(params) { + let isIfr, + bids = params.bids || [], + currentURL = (window.parent !== window) ? document.referrer : window.location.href; + currentURL = currentURL && encodeURIComponent(currentURL); + try { + isIfr = window.self !== window.top; + } + catch (e) { + isIfr = false; + } + if (bids.length === 0) { + return; + } + + _buildRequest(bids, { + pageUrl: currentURL, + did: bids[0].params.did || 0, + pid: bids[0].params.pid || '', + res: _getScreenSize(screen), + ifr: isIfr, + viewPortDim: _getViewportDimensions(isIfr) + }); + } + + function _getScreenSize(screen) { + return screen ? `${screen.width}x${screen.height}x${screen.colorDepth}` : '0'; + } + + function _getViewportDimensions(isIfr) { + let width, + height, + tWin = window, + tDoc = document, + docEl = tDoc.documentElement, + body; + + if (isIfr) { + try { + tWin = window.top; + tDoc = window.top.document; + } + catch (e) { + return; + } + docEl = tDoc.documentElement; + body = tDoc.body; + width = tWin.innerWidth || docEl.clientWidth || body.clientWidth; + height = tWin.innerHeight || docEl.clientHeight || body.clientHeight; + } else { + docEl = tDoc.documentElement; + width = tWin.innerWidth || docEl.clientWidth; + height = tWin.innerHeight || docEl.clientHeight; + } + return `${width}x${height}`; + } + + function _jsonToQueryString(json) { + return '?' + + Object.keys(json).map(function(key) { + return encodeURIComponent(key) + '=' + + encodeURIComponent(json[key]); + }).join('&'); + } + + // Export the `callBids` function, so that Prebid.js can execute + // this function when the page asks to send out bid requests. + return { + callBids: _callBids + }; +} + +adaptermanager.registerBidAdapter(new CarambolaAdapter(), 'carambola'); + +module.exports = CarambolaAdapter; diff --git a/modules/centroBidAdapter.js b/modules/centroBidAdapter.js new file mode 100644 index 00000000000..59abe7cec15 --- /dev/null +++ b/modules/centroBidAdapter.js @@ -0,0 +1,122 @@ +var utils = require('src/utils.js'); +var bidfactory = require('src/bidfactory.js'); +var bidmanager = require('src/bidmanager.js'); +var adloader = require('src/adloader'); +var adaptermanager = require('src/adaptermanager'); + +var CentroAdapter = function CentroAdapter() { + var baseUrl = '//t.brand-server.com/hb', + devUrl = '//staging.brand-server.com/hb', + bidderCode = 'centro', + handlerPrefix = 'adCentroHandler_', + + LOG_ERROR_MESS = { + noUnit: 'Bid has no unit', + noAdTag: 'Bid has missmatch format.', + noBid: 'Response has no bid.', + anotherCode: 'Bid has another bidderCode - ', + undefBid: 'Bid is undefined', + unitNum: 'Requested unit is ' + }; + + function _makeHandler(handlerName, unit, requestedBid) { + return function(response) { + try { + delete window[handlerName]; + } catch (err) { // catching for old IE + window[handlerName] = undefined; + } + _responseProcessing(response, unit, requestedBid); + }; + } + + function _sendBidRequest(requestedBid) { + var bid, size = requestedBid.sizes && requestedBid.sizes[0]; + + bid = requestedBid.params; + if (!bid.unit) { + // throw exception, or call utils.logError + utils.logError(LOG_ERROR_MESS.noUnit, bidderCode); + return; + } + var query = ['s=' + bid.unit, 'adapter=prebid'];//, 'url=www.abc15.com','sz=320x50']; + var isDev = bid.unit.toString() === '28136'; + + query.push('url=' + encodeURIComponent(bid.page_url || location.href)); + // check size format + if ( + size instanceof Array && + size.length === 2 && + typeof size[0] === 'number' && + typeof size[1] === 'number' + ) { + query.push('sz=' + size.join('x')); + } + // make handler name for JSONP request + var handlerName = handlerPrefix + bid.unit + size.join('x') + encodeURIComponent(requestedBid.placementCode); + query.push('callback=' + encodeURIComponent('window["' + handlerName + '"]')); + + // maybe is needed add some random parameter to disable cache + // query.push('r='+Math.round(Math.random() * 1e5)); + + window[handlerName] = _makeHandler(handlerName, bid.unit, requestedBid); + + adloader.loadScript((document.location.protocol === 'https:' ? 'https:' : 'http:') + (isDev ? devUrl : baseUrl) + '?' + query.join('&')); + } + + /* + "sectionID": 7302, + "height": 250, + "width": 300, + "value": 3.2, + "adTag":'' + */ + function _responseProcessing(resp, unit, requestedBid) { + var bidObject; + var bid = resp && resp.bid || resp; + + if (bid && (bid.adTag || bid.statusMessage === 'No bid') && bid.sectionID && bid.sectionID.toString() === unit.toString()) { + if (bid.adTag) { + bidObject = bidfactory.createBid(1, requestedBid); + bidObject.cpm = bid.value; + bidObject.ad = bid.adTag; + bidObject.width = bid.width; + bidObject.height = bid.height; + } else { + bidObject = bidfactory.createBid(2, requestedBid); + } + } else { + // throw exception, or call utils.logError with resp.statusMessage + utils.logError(LOG_ERROR_MESS.unitNum + unit + '. ' + (bid ? bid.statusMessage || LOG_ERROR_MESS.noAdTag : LOG_ERROR_MESS.noBid), bidderCode); + bidObject = bidfactory.createBid(2, requestedBid); + } + bidmanager.addBidResponse(requestedBid.placementCode, bidObject); + } + + /* + { + bidderCode: "centro", + bids: [ + { + unit: '3242432', + page_url: "http://", + size: [300, 250] + */ + function _callBids(params) { + var bid, bids = params.bids || []; + for (var i = 0; i < bids.length; i++) { + bid = bids[i]; + if (bid && bid.bidder === bidderCode) { + _sendBidRequest(bid); + } + } + } + + return { + callBids: _callBids + }; +}; + +adaptermanager.registerBidAdapter(new CentroAdapter(), 'centro'); + +module.exports = CentroAdapter; diff --git a/src/adapters/conversant.js b/modules/conversantBidAdapter.js similarity index 66% rename from src/adapters/conversant.js rename to modules/conversantBidAdapter.js index 3fbada26b95..d51008559f2 100644 --- a/src/adapters/conversant.js +++ b/modules/conversantBidAdapter.js @@ -1,21 +1,22 @@ 'use strict'; -var VERSION = '2.0.1', - CONSTANTS = require('../constants.json'), - utils = require('../utils.js'), - bidfactory = require('../bidfactory.js'), - bidmanager = require('../bidmanager.js'), - adloader = require('../adloader'), - ajax = require('../ajax').ajax; +var VERSION = '2.1.0'; +var CONSTANTS = require('src/constants.json'); +var utils = require('src/utils.js'); +var bidfactory = require('src/bidfactory.js'); +var bidmanager = require('src/bidmanager.js'); +var adloader = require('src/adloader'); +var ajax = require('src/ajax').ajax; +var adaptermanager = require('src/adaptermanager'); /** * Adapter for requesting bids from Conversant */ var ConversantAdapter = function () { - var w = window, - n = navigator; + var w = window; + var n = navigator; // production endpoint - var conversantUrl = '//media.msg.dotomi.com/s2s/header?callback=$$PREBID_GLOBAL$$.conversantResponse'; + var conversantUrl = '//media.msg.dotomi.com/s2s/header/24?callback=$$PREBID_GLOBAL$$.conversantResponse'; // SSAPI returns JSONP with window.pbjs.conversantResponse as the cb var appendScript = function (code) { @@ -55,21 +56,26 @@ var ConversantAdapter = function () { var requestBids = function (bidReqs) { // build bid request object - var page = location.pathname + location.search + location.hash, - siteId = '', - conversantImps = [], - conversantBidReqs, - secure = 0; + var page = location.pathname + location.search + location.hash; + var siteId = ''; + var conversantImps = []; + var conversantBidReqs; + var secure = 0; - //build impression array for conversant + // build impression array for conversant utils._each(bidReqs, function (bid) { - var bidfloor = utils.getBidIdParameter('bidfloor', bid.params), - adW = 0, - adH = 0, - imp; + var bidfloor = utils.getBidIdParameter('bidfloor', bid.params); + var adW = 0; + var adH = 0; + var format; + var tagId; + var pos; + var imp; secure = utils.getBidIdParameter('secure', bid.params) ? 1 : secure; siteId = utils.getBidIdParameter('site_id', bid.params) + ''; + tagId = utils.getBidIdParameter('tag_id', bid.params); + pos = utils.getBidIdParameter('position', bid.params); // Allow sizes to be overridden per placement var bidSizes = Array.isArray(bid.params.sizes) ? bid.params.sizes : bid.sizes; @@ -78,22 +84,69 @@ var ConversantAdapter = function () { adW = bidSizes[0]; adH = bidSizes[1]; } else { - adW = bidSizes[0][0]; - adH = bidSizes[0][1]; + format = []; + utils._each(bidSizes, function (bidSize) { + format.push({ + w: bidSize[0], + h: bidSize[1] + }); + }); } imp = { id: bid.bidId, - banner: { - w: adW, - h: adH - }, secure: secure, - bidfloor: bidfloor ? bidfloor : 0, + bidfloor: bidfloor || 0, displaymanager: 'Prebid.js', displaymanagerver: VERSION }; + if (tagId !== '') { + imp.tagid = tagId; + } + + if (bid.mediaType === 'video') { + var mimes = []; + var maxduration = 0; + var protocols = []; + var api = []; + + var video = Array.isArray(format) ? {format: format} : {w: adW, h: adH}; + + mimes = utils.getBidIdParameter('mimes', bid.params); + if (mimes !== '') { + video.mimes = mimes; + } + + maxduration = utils.getBidIdParameter('maxduration', bid.params); + if (maxduration !== '') { + video.maxduration = maxduration; + } + + protocols = utils.getBidIdParameter('protocols', bid.params); + if (protocols !== '') { + video.protocols = protocols; + } + + api = utils.getBidIdParameter('api', bid.params); + if (api !== '') { + video.api = api; + } + + if (pos !== '') { + video.pos = pos; + } + + imp.video = video; + } else { + var banner = Array.isArray(format) ? {format: format} : {w: adW, h: adH}; + + if (pos !== '') { + banner.pos = pos; + } + imp.banner = banner; + } + conversantImps.push(imp); }); @@ -113,14 +166,14 @@ var ConversantAdapter = function () { var url = secure ? 'https:' + conversantUrl : location.protocol + conversantUrl; ajax(url, appendScript, JSON.stringify(conversantBidReqs), { - withCredentials : true + withCredentials: true }); }; var addEmptyBidResponses = function (placementsWithBidsBack) { var allConversantBidRequests = $$PREBID_GLOBAL$$._bidsRequested.find(bidSet => bidSet.bidderCode === 'conversant'); - if (allConversantBidRequests && allConversantBidRequests.bids){ + if (allConversantBidRequests && allConversantBidRequests.bids) { utils._each(allConversantBidRequests.bids, function (conversantBid) { if (!utils.contains(placementsWithBidsBack, conversantBid.placementCode)) { // Add a no-bid response for this placement. @@ -135,13 +188,13 @@ var ConversantAdapter = function () { var parseSeatbid = function (bidResponse) { var placementsWithBidsBack = []; utils._each(bidResponse.bid, function (conversantBid) { - var responseCPM, - placementCode = '', - id = conversantBid.impid, - bid = {}, - responseAd, - responseNurl, - sizeArrayLength; + var responseCPM; + var placementCode = ''; + var id = conversantBid.impid; + var bid = {}; + var responseAd; + var responseNurl; + var sizeArrayLength; // Bid request we sent Conversant var bidRequested = $$PREBID_GLOBAL$$._bidsRequested.find(bidSet => bidSet.bidderCode === 'conversant').bids.find(bid => bid.bidId === id); @@ -162,11 +215,14 @@ var ConversantAdapter = function () { bid = bidfactory.createBid(1, bidRequested); bid.creative_id = conversantBid.id || ''; bid.bidderCode = 'conversant'; - bid.cpm = responseCPM; - // Track impression image onto returned html - bid.ad = responseAd + ''; + if (bidRequested.mediaType === 'video') { + bid.vastUrl = responseAd; + } else { + // Track impression image onto returned html + bid.ad = responseAd + ''; + } sizeArrayLength = bidRequested.sizes.length; if (sizeArrayLength === 2 && typeof bidRequested.sizes[0] === 'number' && typeof bidRequested.sizes[1] === 'number') { @@ -191,19 +247,19 @@ var ConversantAdapter = function () { if (conversantResponseObj.seatbid && conversantResponseObj.seatbid.length > 0 && conversantResponseObj.seatbid[0].bid && conversantResponseObj.seatbid[0].bid.length > 0) { utils._each(conversantResponseObj.seatbid, parseSeatbid); } else { - //no response data for any placements + // no response data for any placements addEmptyBidResponses([]); } } else { - //no response data for any placements + // no response data for any placements addEmptyBidResponses([]); } // for debugging purposes - if (path){ + if (path) { adloader.loadScript(path, function () { var allConversantBidRequests = $$PREBID_GLOBAL$$._bidsRequested.find(bidSet => bidSet.bidderCode === 'conversant'); - if ($$PREBID_GLOBAL$$.conversantDebugResponse){ + if ($$PREBID_GLOBAL$$.conversantDebugResponse) { $$PREBID_GLOBAL$$.conversantDebugResponse(allConversantBidRequests); } }); @@ -215,4 +271,8 @@ var ConversantAdapter = function () { }; }; +adaptermanager.registerBidAdapter(new ConversantAdapter(), 'conversant', { + supportedMediaTypes: ['video'] +}); + module.exports = ConversantAdapter; diff --git a/modules/coxBidAdapter.js b/modules/coxBidAdapter.js new file mode 100644 index 00000000000..432b82ebf88 --- /dev/null +++ b/modules/coxBidAdapter.js @@ -0,0 +1,258 @@ +var bidfactory = require('src/bidfactory.js'); +var bidmanager = require('src/bidmanager.js'); +var adLoader = require('src/adloader.js'); +var adaptermanager = require('src/adaptermanager'); + +function CoxAdapter() { + var adZoneAttributeKeys = ['id', 'size', 'thirdPartyClickUrl'], + otherKeys = ['siteId', 'wrapper', 'referrerUrl'], + placementMap = {}, + W = window; + + var COX_BIDDER_CODE = 'cox'; + + function _callBids(params) { + var env = ''; + + // Create global cdsTag and CMT object (for the latter, only if needed ) + W.cdsTag = {}; + if (!W.CMT) W.CMT = _getCoxLite(); + + // Populate the tag with the info from prebid + var bids = params.bids || [], + tag = W.cdsTag, + i, + j; + for (i = 0; i < bids.length; i++) { + var bid = bids[i], + cfg = bid.params || {}; + + if (cfg.id) { + tag.zones = tag.zones || {}; + var zone = {}; + + for (j = 0; j < adZoneAttributeKeys.length; j++) { + if (cfg[adZoneAttributeKeys[j]]) zone[adZoneAttributeKeys[j]] = cfg[adZoneAttributeKeys[j]]; + } + for (j = 0; j < otherKeys.length; j++) { + if (cfg[otherKeys[j]]) tag[otherKeys[j]] = cfg[otherKeys[j]]; + } + var adZoneKey = 'as' + cfg.id; + tag.zones[adZoneKey] = zone; + + // Check for an environment setting + if (cfg.env) env = cfg.env; + + // Update the placement map + var xy = (cfg.size || '0x0').split('x'); + placementMap[adZoneKey] = { + p: bid.placementCode, + w: xy[0], + h: xy[1] + }; + } + } + if (tag.zones && Object.keys(tag.zones).length > 0) { + tag.__callback__ = function (r) { + tag.response = r; + _notify(); + }; + adLoader.loadScript(W.CMT.Service.buildSrc(tag, env)); + } + } + + function _notify() { + // Will execute in the context of a bid + // function finalizeAd(price) { + // this.ad = W.CMT.Service.setAuctionPrice(this.ad, price); + // return this; + // } + + for (var adZoneKey in placementMap) { + var bid = W.CMT.Service.getBidTrue(adZoneKey), + bidObj, + data = placementMap[adZoneKey]; + + if (bid > 0) { + bidObj = bidfactory.createBid(1); + bidObj.cpm = bid; + bidObj.ad = W.CMT.Service.getAd(adZoneKey); + bidObj.width = data.w; + bidObj.height = data.h; + // bidObj.floor = W.CMT.Service.getSecondPrice(adZoneKey); + // bidObj.finalizeAd = finalizeAd; + } else { + bidObj = bidfactory.createBid(2); + } + bidObj.bidderCode = COX_BIDDER_CODE; + bidmanager.addBidResponse(data.p, bidObj); + } + } + + function _getCoxLite() { + var CMT = {}; + + CMT.Util = (function () { + return { + + getRand: function getRand() { + return Math.round(Math.random() * 100000000); + }, + + encodeUriObject: function encodeUriObject(obj) { + return encodeURIComponent(JSON.stringify(obj)); + }, + + extractUrlInfo: function extractUrlInfo() { + function f2(callback) { + try { + if (!W.location.ancestorOrigins) return; + for (var i = 0, len = W.location.ancestorOrigins.length; len > i; i++) { + callback.call(null, W.location.ancestorOrigins[i], i); + } + } catch (ignore) { } + return []; + } + + function f1(callback) { + var oneWindow, + infoArray = []; + do { + try { + oneWindow = oneWindow ? oneWindow.parent : W; + callback.call(null, oneWindow, infoArray); + } catch (t) { + infoArray.push({ + referrer: null, + location: null, + isTop: !1 + }); + return infoArray; + } + } while (oneWindow !== W.top); + return infoArray; + } + var allInfo = f1(function (oneWindow, infoArray) { + try { + infoArray.push({ referrer: oneWindow.document.referrer || null, location: oneWindow.location.href || null, isTop: oneWindow === W.top }); + } catch (e) { + infoArray.push({ referrer: null, location: null, isTop: oneWindow === W.top }); + } + }); + f2(function (n, r) { + allInfo[r].ancestor = n; + }); + for (var t = '', e = !1, i = allInfo.length - 1, l = allInfo.length - 1; l >= 0; l--) { + t = allInfo[l].location; + if (!t && l > 0) { + t = allInfo[l - 1].referrer; + if (!t) t = allInfo[l - 1].ancestor; + if (t) { + e = W.location.ancestorOrigins ? !0 : l === allInfo.length - 1 && allInfo[allInfo.length - 1].isTop; + break; + } + } + } return { url: t, isTop: e, depth: i }; + }, + + srTestCapabilities: function srTestCapabilities() { + var plugins = navigator.plugins, + flashVer = -1, + sf = 'Shockwave Flash'; + + if (plugins && plugins.length > 0) { + if (plugins[sf + ' 2.0'] || plugins[sf]) { + var swVer2 = plugins[sf + ' 2.0'] ? ' 2.0' : ''; + var flashDescription = plugins[sf + swVer2].description; + flashVer = flashDescription.split(' ')[2].split('.')[0]; + } + } + if (flashVer > 4) return 15; else return 7; + } + + }; + }()); + + // Ad calling functionality + CMT.Service = (function () { + // Closure variables shared by the service functions + var U = CMT.Util; + + return { + + buildSrc: function buildSrc(tag, env) { + var src = (document.location.protocol === 'https:' ? 'https://' : 'http://') + (!env || env === 'PRD' ? '' : env === 'PPE' ? 'ppe-' : env === 'STG' ? 'staging-' : '') + 'ad.afy11.net/ad' + '?mode=11' + '&ct=' + U.srTestCapabilities() + '&nif=0' + '&sf=0' + '&sfd=0' + '&ynw=0' + '&rand=' + U.getRand() + '&hb=1' + '&rk1=' + U.getRand() + '&rk2=' + new Date().valueOf() / 1000; + + // Make sure we don't have a response object... + delete tag.response; + + // Extracted url info... + var urlInfo = U.extractUrlInfo(); + tag.pageUrl = urlInfo.url; + tag.puTop = urlInfo.isTop; + + // Attach the serialized tag to our string + src += '&ab=' + U.encodeUriObject(tag); + + return src; + }, + + getAd: function (zoneKey) { + if (!zoneKey) return; + + return this._getData(zoneKey, 'ad') + (this._getResponse().tpCookieSync || ''); // ...also append cookie sync if present + }, + + // getSecondPrice: function getSecondPrice(zoneKey) { + // if (zoneKey.substring(0, 2) !== 'as') zoneKey = 'as' + zoneKey; + // var bid = this.getBidTrue(zoneKey), + // floor = this._getData(zoneKey, 'floor'); + + // // If no floor, just set it to 80% of the bid + // if (!floor) floor = bid * 0.80; + + // // Adjust the floor if it's too high...it needs to always be lower + // if (floor >= bid) { + // floor = floor * 0.80; // Take off 20% to account for possible non-adjusted 2nd highest bid + + // // If it's still too high, just take 80% to 90% of the bid + // if (floor >= bid) floor = bid * ((Math.random() * 10) + 80) / 100; + // } + // return Math.round(floor * 100) / 100; + // }, + + // setAuctionPrice: function setAuctionPrice(ad, bid) { + // return ad ? ad.replace('${AUCTION_PRICE}', bid) : ad; + // }, + + getBidTrue: function getBidTrue(zoneKey) { + return Math.round(this._getData(zoneKey, 'price') * 100) / 100; + }, + + _getData: function (zoneKey, field) { + var response = this._getResponse(), + zoneResponseData = response.zones ? response.zones[zoneKey] : {}; + + return (zoneResponseData || {})[field] || null; + }, + + _getResponse: function () { + var tag = W.cdsTag; + return (tag && tag.response) ? tag.response : {}; + }, + }; + }()); + + return CMT; + } + + // Export the callBids function, so that prebid.js can execute this function + // when the page asks to send out bid requests. + return { + callBids: _callBids, + }; +} + +adaptermanager.registerBidAdapter(new CoxAdapter(), 'cox'); + +module.exports = CoxAdapter; diff --git a/src/adapters/criteo.js b/modules/criteoBidAdapter.js similarity index 78% rename from src/adapters/criteo.js rename to modules/criteoBidAdapter.js index eb1c522350a..8fd74ff83fa 100644 --- a/src/adapters/criteo.js +++ b/modules/criteoBidAdapter.js @@ -1,10 +1,11 @@ -var bidfactory = require('../bidfactory.js'); -var bidmanager = require('../bidmanager.js'); -var adloader = require('../adloader'); +var bidfactory = require('src/bidfactory.js'); +var bidmanager = require('src/bidmanager.js'); +var adloader = require('src/adloader'); +var adaptermanager = require('src/adaptermanager'); var CriteoAdapter = function CriteoAdapter() { - - var _publisherTagUrl = window.location.protocol + '//static.criteo.net/js/ld/publishertag.js'; + var sProt = (window.location.protocol === 'http:') ? 'http:' : 'https:'; + var _publisherTagUrl = sProt + '//static.criteo.net/js/ld/publishertag.js'; var _bidderCode = 'criteo'; var _profileId = 125; @@ -15,11 +16,10 @@ var CriteoAdapter = function CriteoAdapter() { _pushBidRequestEvent(params); adloader.loadScript( _publisherTagUrl, - function () {}, + function () { }, true ); - } - else { + } else { // publisherTag already loaded _pushBidRequestEvent(params); } @@ -27,14 +27,12 @@ var CriteoAdapter = function CriteoAdapter() { // send bid request to criteo direct bidder handler function _pushBidRequestEvent(params) { - // if we want to be fully asynchronous, we must first check window.criteo_pubtag in case publishertag.js is not loaded yet. window.Criteo = window.Criteo || {}; window.Criteo.events = window.Criteo.events || []; // generate the bidding event var biddingEventFunc = function () { - var bids = params.bids || []; var slots = []; @@ -44,15 +42,22 @@ var CriteoAdapter = function CriteoAdapter() { // build slots before sending one multi-slots bid request for (var i = 0; i < bids.length; i++) { var bid = bids[i]; + var sizes = bid.sizes || []; slots.push( new Criteo.PubTag.DirectBidding.DirectBiddingSlot( bid.placementCode, bid.params.zoneId, undefined, - bid.transactionId + bid.transactionId, + sizes.map((size) => { + return { width: size[0], height: size[1] } + } + ) ) ); + var networkid = bid.params.networkId; + isAudit |= bid.params.audit !== undefined; } @@ -62,7 +67,9 @@ var CriteoAdapter = function CriteoAdapter() { slots, _callbackSuccess(slots), _callbackError(slots), - _callbackError(slots) // timeout handled as error + _callbackError(slots), // timeout handled as error + undefined, + networkid ); // process the event as soon as possible @@ -70,14 +77,12 @@ var CriteoAdapter = function CriteoAdapter() { }; window.Criteo.events.push(biddingEventFunc); - } function parseBidResponse(bidsResponse) { try { return JSON.parse(bidsResponse); - } - catch (error) { + } catch (error) { return {}; } } @@ -90,8 +95,7 @@ var CriteoAdapter = function CriteoAdapter() { return function (bidsResponse) { var jsonbidsResponse = parseBidResponse(bidsResponse); - if (isNoBidResponse(jsonbidsResponse)) - return _callbackError(slots)(); + if (isNoBidResponse(jsonbidsResponse)) { return _callbackError(slots)(); } for (var i = 0; i < slots.length; i++) { var bidResponse = null; @@ -113,8 +117,7 @@ var CriteoAdapter = function CriteoAdapter() { bidObject.ad = bidResponse.creative; bidObject.width = bidResponse.width; bidObject.height = bidResponse.height; - } - else { + } else { bidObject = _invalidBidResponse(); } bidmanager.addBidResponse(slots[i].impId, bidObject); @@ -141,4 +144,6 @@ var CriteoAdapter = function CriteoAdapter() { }; }; -module.exports = CriteoAdapter; \ No newline at end of file +adaptermanager.registerBidAdapter(new CriteoAdapter(), 'criteo'); + +module.exports = CriteoAdapter; diff --git a/modules/dfpAdServerVideo.js b/modules/dfpAdServerVideo.js new file mode 100644 index 00000000000..d73fa53802f --- /dev/null +++ b/modules/dfpAdServerVideo.js @@ -0,0 +1,88 @@ +/** + * This module adds [DFP support]{@link https://www.doubleclickbygoogle.com/} for Video to Prebid. + */ + +import { registerVideoSupport } from '../src/adServerManager'; +import { getWinningBids } from '../src/targeting'; +import { formatQS, format as buildUrl } from '../src/url'; +import { parseSizesInput } from '../src/utils'; + +/** + * @typedef {Object} DfpVideoParams + * + * This object contains the params needed to form a URL which hits the + * [DFP API]{@link https://support.google.com/dfp_premium/answer/1068325?hl=en}. + * + * All params (except iu, mentioned below) should be considered optional. This module will choose reasonable + * defaults for all of the other required params. + * + * The cust_params property, if present, must be an object. It will be merged with the rest of the + * standard Prebid targeting params (hb_adid, hb_bidder, etc). + * + * @param {string} iu This param *must* be included, in order for us to create a valid request. + * @param [string] description_url This field is required if you want Ad Exchange to bid on our ad unit... + * but otherwise optional + */ + +/** + * @typedef {Object} DfpVideoOptions + * + * @param {Object} adUnit The adUnit which this bid is supposed to help fill. + * @param [Object] bid The bid which should be considered alongside the rest of the adserver's demand. + * If this isn't defined, then we'll use the winning bid for the adUnit. + * + * @param {DfpVideoParams} params Query params which should be set on the DFP request. + * These will override this module's defaults whenever they conflict. + */ + +/** Safe defaults which work on pretty much all video calls. */ +const defaultParamConstants = { + env: 'vp', + gdfp_req: 1, + output: 'xml_vast3', + unviewed_position_start: 1, +}; + +/** + * Merge all the bid data and publisher-supplied options into a single URL, and then return it. + * + * @see [The DFP API]{@link https://support.google.com/dfp_premium/answer/1068325?hl=en#env} for details. + * + * @param {DfpVideoOptions} options Options which should be used to construct the URL. + * + * @return {string} A URL which calls DFP, letting options.bid + * (or the auction's winning bid for this adUnit, if undefined) compete alongside the rest of the + * demand in DFP. + */ +export default function buildDfpVideoUrl(options) { + const adUnit = options.adUnit; + const bid = options.bid || getWinningBids(adUnit.code)[0]; + + const derivedParams = { + correlator: Date.now(), + sz: parseSizesInput(adUnit.sizes).join('|'), + url: location.href, + }; + + const customParams = Object.assign({}, + bid.adserverTargeting, + { hb_uuid: bid.videoCacheKey }, + options.params.cust_params); + + const queryParams = Object.assign({}, + defaultParamConstants, + derivedParams, + options.params, + { cust_params: encodeURIComponent(formatQS(customParams))}); + + return buildUrl({ + protocol: 'https', + host: 'pubads.g.doubleclick.net', + pathname: '/gampad/ads', + search: queryParams + }); +} + +registerVideoSupport('dfp', { + buildVideoUrl: buildDfpVideoUrl +}); diff --git a/src/adapters/districtmDMX.js b/modules/districtmDMXBidAdapter.js similarity index 62% rename from src/adapters/districtmDMX.js rename to modules/districtmDMXBidAdapter.js index 9dd6bf4c36d..65a51ecc475 100644 --- a/src/adapters/districtmDMX.js +++ b/modules/districtmDMXBidAdapter.js @@ -1,24 +1,24 @@ -var bidfactory = require('../bidfactory.js'); -var bidmanager = require('../bidmanager.js'); -var adLoader = require('../adloader'); +var bidfactory = require('src/bidfactory.js'); +var bidmanager = require('src/bidmanager.js'); +var adLoader = require('src/adloader'); +var adaptermanager = require('src/adaptermanager'); -var DistrictmAdaptor = function districtmAdaptor(){ +var DistrictmAdaptor = function districtmAdaptor() { let districtmUrl = window.location.protocol + '//prebid.districtm.ca/lib.js'; - this.callBids = params =>{ - if(!window.hb_dmx_res){ - adLoader.loadScript(districtmUrl,()=>{ + this.callBids = params => { + if (!window.hb_dmx_res) { + adLoader.loadScript(districtmUrl, () => { this.sendBids(params); }); - }else{ + } else { this.sendBids(params); } return params; }; - - this.handlerRes = function(response, bidObject){ + this.handlerRes = function(response, bidObject) { let bid; - if(parseFloat(response.result.cpm) > 0){ + if (parseFloat(response.result.cpm) > 0) { bid = bidfactory.createBid(1); bid.bidderCode = bidObject.bidder; bid.cpm = response.result.cpm; @@ -26,7 +26,7 @@ var DistrictmAdaptor = function districtmAdaptor(){ bid.height = response.result.height; bid.ad = response.result.banner; bidmanager.addBidResponse(bidObject.placementCode, bid); - }else{ + } else { bid = bidfactory.createBid(2); bid.bidderCode = bidObject.bidder; bidmanager.addBidResponse(bidObject.placementCode, bid); @@ -35,17 +35,15 @@ var DistrictmAdaptor = function districtmAdaptor(){ return bid; }; - - this.sendBids = function(params){ + this.sendBids = function(params) { var bids = params.bids; - for(var i = 0; i < bids.length; i++){ + for (var i = 0; i < bids.length; i++) { bids[i].params.sizes = window.hb_dmx_res.auction.fixSize(bids[i].sizes); } window.hb_dmx_res.auction.run(window.hb_dmx_res.ssp, bids, this.handlerRes); return bids; }; - return { callBids: this.callBids, sendBids: this.sendBids, @@ -53,4 +51,6 @@ var DistrictmAdaptor = function districtmAdaptor(){ }; }; +adaptermanager.registerBidAdapter(new DistrictmAdaptor(), 'districtmDMX'); + module.exports = DistrictmAdaptor; diff --git a/modules/eplanningBidAdapter.js b/modules/eplanningBidAdapter.js new file mode 100644 index 00000000000..aa2e0d8cea7 --- /dev/null +++ b/modules/eplanningBidAdapter.js @@ -0,0 +1,283 @@ +var bidfactory = require('src/bidfactory.js'); +var bidmanager = require('src/bidmanager.js'); +var adaptermanager = require('src/adaptermanager'); + +function EPlanningAdapter() { + (function() { + var win = window, doc = win.document, pbjsVar = win.$$PREBID_GLOBAL$$, _global = {}, _default = { 'sv': 'ads.us.e-planning.net', 't': 0 }, rnd, FILE = 'file', CALLBACK_FUNCTION = 'hbpb.rH', NULL_SIZE = '1x1', _csRequested = [], PROTO = location.protocol === 'https:' ? 'https:' : 'http:', ISV = 'aklc.img.e-planning.net'; + function Hbpb() { + var slots = (function() { + var _data = []; + function Slot(slotId) { + var data = _data[slotId]; + function hasAds() { + return _data[slotId].ads.length; + } + function getSizes() { + return data.sizes; + } + function getSizesString() { + var s = [], i, sizes = getSizes(); + if (sizes && sizes.length) { + if (typeof sizes[0] === 'object') { + for (i = 0; i < sizes.length; i++) { + s.push(sizes[i][0] + 'x' + sizes[i][1]); + } + } else { + s.push(sizes[0] + 'x' + sizes[1]); + } + } else { + return NULL_SIZE; + } + return s.join(','); + } + return { + getPlacementCode: function() { + return data.placementCode; + }, + getString: function() { + return this.getPlacementCode() + ':' + getSizesString(); + }, + addAd: function(ad) { + _data[slotId].ads.push(ad); + }, + getFormatedResponse: function() { + var ad, that = this; + if (hasAds()) { + ad = data.ads[0]; + return { + 'placementCode': that.getPlacementCode(), + 'ad': { + 'ad': ad.adm, + 'cpm': ad.pr, + 'width': ad.size.w, + 'height': ad.size.h + } + }; + } else { + return { 'placementCode': that.getPlacementCode() }; + } + } + }; + } + function findAll() { + var i = 0, r = []; + for (i = 0; i < _data.length; i++) { + r.push(new Slot(i)); + } + return r; + } + return { + add: function(slot) { + slot.ads = []; + _data.push(slot); + }, + get: function(slotId) { + return new Slot(slotId); + }, + getString: function() { + var _slots = [], i, slot; + for (i = 0; i < _data.length; i++) { + slot = this.get(i); + _slots.push(slot.getString()); + } + return _slots.join('+'); + }, + findByPlacementCode: function(placementCode) { + var i, _slots = findAll(); + for (i = 0; i < _slots.length; i++) { + if (_slots[i].getPlacementCode() === placementCode) { + return _slots[i]; + } + } + }, + getFormatedResponse: function() { + var _slots = findAll(), i, r = []; + for (i = 0; i < _slots.length; i++) { + r.push(_slots[i].getFormatedResponse()); + } + return { + 'bids': r + }; + } + }; + })(); + function call(params) { + var i, bids = params.bids; + for (i = 0; i < bids.length; i++) { + slots.add({ + _raw: bids[i], + placementCode: bids[i].placementCode, + sizes: bids[i].sizes + }); + setGlobalParam('sv', bids[i]); + setGlobalParam('ci', bids[i]); + setGlobalParam('t', bids[i]); + } + doRequest(); + } + function setGlobalParam(param, bid) { + if (!_global[param]) { + if (bid && bid.params && bid.params[param]) { + _global[param] = bid.params[param]; + } + } + } + function getGlobalParam(param) { + return (_global[param] || _default[param]); + } + function getRandom() { + if (!rnd) { + rnd = Math.random(); + } + return rnd; + } + function getDocURL() { + return escape(win.location.href || FILE); + } + function getReferrerURL() { + return doc.referrer; + } + function getCallbackFunction() { + return CALLBACK_FUNCTION; + } + function doRequest() { + var clienteId = getGlobalParam('ci'), url, dfpClienteId = '1', sec = 'ROS', params = [], t = getGlobalParam('t'); + if (clienteId && !t) { + url = PROTO + '//' + getGlobalParam('sv') + '/hb/1/' + clienteId + '/' + dfpClienteId + '/' + (win.location.hostname || FILE) + '/' + sec + '?'; + params.push('rnd=' + getRandom()); + params.push('e=' + slots.getString()); + if (getDocURL()) { + params.push('ur=' + getDocURL()); + } + if (getReferrerURL()) { + params.push('fr=' + getReferrerURL()); + } + params.push('cb=' + getCallbackFunction()); + params.push('r=pbjs'); + url += params.join('&'); + load(url); + } else if (t) { + url = PROTO + '//' + ISV + '/layers/t_pbjs_' + t + '.js'; + load(url); + } + } + function load(url) { + var script = doc.createElement('script'); + script.src = url; + doc.body.appendChild(script); + } + function callback(response) { + if (pbjsVar && pbjsVar.processEPlanningResponse && typeof pbjsVar.processEPlanningResponse === 'function') { + pbjsVar.processEPlanningResponse(response); + } + } + function syncUsers(cs) { + var i, e, d; + for (i = 0; i < cs.length; i++) { + if (typeof cs[i] === 'string' && _csRequested.indexOf(cs[i]) === -1) { + (new Image()).src = cs[i]; + _csRequested.push(cs[i]); + } else if (typeof cs[i] === 'object' && _csRequested.indexOf(cs[i].u) === -1) { + if (cs[i].j) { + e = doc.createElement('script'); + e.src = cs[i].u; + } else if (cs[i].ifr) { + e = doc.createElement('iframe'); + e.src = cs[i].u; + e.style.width = e.style.height = '1px'; + e.display = 'none'; + } + if (cs[i].data) { + for (d in cs[i].data) { + if (cs[i].data.hasOwnProperty(d)) { + e.setAttribute('data-' + d, cs[i].data[d]); + } + } + } + doc.body.appendChild(e); + _csRequested.push(cs[i].u); + } + } + } + function rH(response) { + var slot, i, o; + if (response && response.sp && response.sp.length) { + for (i = 0; i < response.sp.length; i++) { + if (response.sp[i].a) { + slot = slots.findByPlacementCode(response.sp[i].k); + if (slot) { + for (o = 0; o < response.sp[i].a.length; o++) { + slot.addAd({ + 'adm': response.sp[i].a[o].adm, + 'pr': response.sp[i].a[o].pr, + 'size': { + 'w': response.sp[i].a[o].w, + 'h': response.sp[i].a[o].h + } + }); + } + } + } + } + callback(slots.getFormatedResponse()); + } + if (response && response.cs && response.cs.length) { + syncUsers(response.cs); + } + } + return { + call: function(params) { + return call(params); + }, + rH: function(response) { + return rH(response); + } + }; + } + win.hbpb = win.hbpb || new Hbpb(); + })(); + + window.$$PREBID_GLOBAL$$ = window.$$PREBID_GLOBAL$$ || {}; + window.$$PREBID_GLOBAL$$.processEPlanningResponse = function(response) { + var bids, bidObject, i; + if (response) { + bids = response.bids; + for (i = 0; i < bids.length; i++) { + if (bids[i].ad) { + bidObject = getBidObject(bids[i]); + bidmanager.addBidResponse(bids[i].placementCode, bidObject); + } else { + bidObject = bidfactory.createBid(2); + bidObject.bidderCode = 'eplanning'; + bidmanager.addBidResponse(bids[i].placementCode, bidObject); + } + } + } + }; + + function getBidObject(bid) { + var bidObject = bidfactory.createBid(1), i; + bidObject.bidderCode = 'eplanning'; + for (i in bid.ad) { + if (bid.ad.hasOwnProperty(i)) { + bidObject[i] = bid.ad[i]; + } + } + return bidObject; + } + + function _callBids(params) { + if (window.hbpb) { + window.hbpb.call(params); + } + } + + return { + callBids: _callBids + }; +} + +adaptermanager.registerBidAdapter(new EPlanningAdapter(), 'eplanning'); + +module.exports = EPlanningAdapter; diff --git a/modules/express.js b/modules/express.js new file mode 100644 index 00000000000..20921276cfe --- /dev/null +++ b/modules/express.js @@ -0,0 +1,206 @@ + +import * as utils from 'src/utils'; + +const MODULE_NAME = 'express'; + +/** + * Express Module + * + * The express module allows the initiation of Prebid.js auctions automatically based on calls such as gpt.defineSlot. + * It works by monkey-patching the gpt methods and overloading their functionality. In order for this module to be + * used gpt must be included in the page, this module must be included in the Prebid.js bundle, and a call to + * pbjs.express() must be made. + * + * @param {Object[]} [adUnits = pbjs.adUnits] - an array of adUnits for express to operate on. + */ +$$PREBID_GLOBAL$$.express = function(adUnits = $$PREBID_GLOBAL$$.adUnits) { + utils.logMessage('loading ' + MODULE_NAME); + + if (adUnits.length === 0) { + utils.logWarn('no valid adUnits found, not loading ' + MODULE_NAME); + } + + // put adUnits in a more performant hash lookup by code. + var adUnitsCache = adUnits.reduce(function (cache, adUnit) { + if (adUnit.code && adUnit.bids) { + cache[adUnit.code] = adUnit; + } else { + utils.logError('misconfigured adUnit', null, adUnit); + } + return cache; + }, {}); + + window.googletag = window.googletag || {}; + window.googletag.cmd = window.googletag.cmd || []; + window.googletag.cmd.push(function () { + // verify all necessary gpt functions exist + var gpt = window.googletag; + var pads = gpt.pubads; + if (!gpt.display || !gpt.enableServices || typeof pads !== 'function' || !pads().refresh || !pads().disableInitialLoad || !pads().getSlots || !pads().enableSingleRequest) { + utils.logError('could not bind to gpt googletag api'); + return; + } + utils.logMessage('running'); + + + // function to convert google tag slot sizes to [[w,h],...] + function mapGptSlotSizes(aGPTSlotSizes) { + var aSlotSizes = []; + for (var i = 0; i < aGPTSlotSizes.length; i++) { + try { + aSlotSizes.push([aGPTSlotSizes[i].getWidth(), aGPTSlotSizes[i].getHeight()]); + } catch (e) { + utils.logWarn('slot size ' + aGPTSlotSizes[i].toString() + ' not supported by' + MODULE_NAME); + } + } + return aSlotSizes; + } + + // a helper function to verify slots or get slots if not present + function defaultSlots(slots) { + return Array.isArray(slots) + ? slots.slice() + : googletag.pubads().getSlots().slice(); + } + + // maps gpt slots to adUnits, matches are copied to new array and removed from passed array. + function pickAdUnits(gptSlots) { + var adUnits = []; + // traverse backwards (since gptSlots is mutated) to find adUnits in cache and remove non-mapped slots + for (var i = gptSlots.length - 1; i > -1; i--) { + var gptSlot = gptSlots[i], + elemId = gptSlot.getSlotElementId(), + adUnit = adUnitsCache[elemId]; + + if (adUnit) { + adUnit._gptSlot = gptSlot; + adUnit.sizes = adUnit.sizes || mapGptSlotSizes(gptSlot.getSizes()); + adUnits.push(adUnit); + gptSlots.splice(i, 1); + } + } + + return adUnits; + } + + // store original gpt functions that will be overridden + var fGptDisplay = gpt.display; + var fGptEnableServices = gpt.enableServices; + var fGptRefresh = pads().refresh; + var fGptDisableInitialLoad = pads().disableInitialLoad; + var fGptEnableSingleRequest = pads().enableSingleRequest; + + // override googletag.enableServices() + // - make sure fGptDisableInitialLoad() has been called so we can + // better control when slots are displayed, then call original + // fGptEnableServices() + gpt.enableServices = function () { + if (!bInitialLoadDisabled) { + fGptDisableInitialLoad.apply(pads()); + } + return fGptEnableServices.apply(gpt, arguments); + }; + + // override googletag.display() + // - call the real fGptDisplay(). this won't initiate auctions because we've disabled initial load + // - define all corresponding rubicon slots + // - if disableInitialLoad() has been called by the pub, done + // - else run an auction and call the real fGptRefresh() to + // initiate the DFP request + gpt.display = function (sElementId) { + utils.logInfo('display:', sElementId); + // call original gpt display() function + fGptDisplay.apply(gpt, arguments); + + // if not SRA mode, get only the gpt slot corresponding to sEementId + var aGptSlots; + if (!bEnabledSRA) { + aGptSlots = googletag.pubads().getSlots().filter(function (oGptSlot) { + return oGptSlot.getSlotElementId() === sElementId; + }); + } + + aGptSlots = defaultSlots(aGptSlots).filter(function (gptSlot) { + return !gptSlot._displayed; + }); + + aGptSlots.forEach(function (gptSlot) { + gptSlot._displayed = true; + }); + + var adUnits = pickAdUnits(/* mutated: */ aGptSlots); + + if (!bInitialLoadDisabled) { + if (aGptSlots.length) { + fGptRefresh.apply(pads(), [aGptSlots]); + } + + if (adUnits.length) { + $$PREBID_GLOBAL$$.requestBids({ + adUnits: adUnits, + bidsBackHandler: function () { + $$PREBID_GLOBAL$$.setTargetingForGPTAsync(); + fGptRefresh.apply(pads(), [ + adUnits.map(function (adUnit) { + return adUnit._gptSlot; + }) + ]); + } + }); + } + } + }; + + // override gpt refresh() function + // - run auctions for provided gpt slots, then initiate ad-server call + pads().refresh = function (aGptSlots, options) { + utils.logInfo('refresh:', aGptSlots); + // get already displayed adUnits from aGptSlots if provided, else all defined gptSlots + aGptSlots = defaultSlots(aGptSlots); + var adUnits = pickAdUnits(/* mutated: */ aGptSlots).filter(function (adUnit) { + return adUnit._gptSlot._displayed; + }); + + if (aGptSlots.length) { + fGptRefresh.apply(pads(), [aGptSlots, options]); + } + + if (adUnits.length) { + $$PREBID_GLOBAL$$.requestBids({ + adUnits: adUnits, + bidsBackHandler: function () { + $$PREBID_GLOBAL$$.setTargetingForGPTAsync(); + fGptRefresh.apply(pads(), [ + adUnits.map(function (adUnit) { + return adUnit._gptSlot + }), + options + ]); + } + }); + } + }; + + // override gpt disableInitialLoad function + // Register that initial load was called, meaning calls to display() + // should not initiate an ad-server request. Instead a call to + // refresh() will be needed to iniate the request. + // We will assume the pub is using this the correct way, calling it + // before enableServices() + var bInitialLoadDisabled = false; + pads().disableInitialLoad = function () { + bInitialLoadDisabled = true; + return fGptDisableInitialLoad.apply(window.googletag.pubads(), arguments); + }; + + // override gpt useSingleRequest function + // Register that SRA has been turned on + // We will assume the pub is using this the correct way, calling it + // before enableServices() + var bEnabledSRA = false; + pads().enableSingleRequest = function () { + bEnabledSRA = true; + return fGptEnableSingleRequest.apply(window.googletag.pubads(), arguments); + }; + }); +}; diff --git a/src/adapters/fidelity.js b/modules/fidelityBidAdapter.js similarity index 71% rename from src/adapters/fidelity.js rename to modules/fidelityBidAdapter.js index 66550219561..73ee9d44ddd 100644 --- a/src/adapters/fidelity.js +++ b/modules/fidelityBidAdapter.js @@ -1,8 +1,9 @@ -var utils = require('../utils.js'); -var bidfactory = require('../bidfactory.js'); -var bidmanager = require('../bidmanager.js'); -var adloader = require('../adloader'); -var STATUS = require('../constants').STATUS; +var utils = require('src/utils.js'); +var bidfactory = require('src/bidfactory.js'); +var bidmanager = require('src/bidmanager.js'); +var adloader = require('src/adloader'); +var STATUS = require('src/constants').STATUS; +var adaptermanager = require('src/adaptermanager'); var FidelityAdapter = function FidelityAdapter() { var FIDELITY_BIDDER_NAME = 'fidelity'; @@ -12,13 +13,13 @@ var FidelityAdapter = function FidelityAdapter() { var bids = params.bids || []; bids.forEach(function (currentBid) { var server = currentBid.params.server || FIDELITY_SERVER_NAME; - var m3_u = window.location.protocol + '//'+server+'/delivery/hb.php?'; + var m3_u = window.location.protocol + '//' + server + '/delivery/hb.php?'; m3_u += 'callback=window.$$PREBID_GLOBAL$$.fidelityResponse'; - m3_u += '&requestid='+utils.getUniqueIdentifierStr(); - m3_u += '&impid='+currentBid.bidId; - m3_u += '&zoneid='+currentBid.params.zoneid; - m3_u += '&cb='+Math.floor(Math.random()*99999999999); - m3_u += document.charset ? '&charset='+document.charset : (document.characterSet ? '&charset='+document.characterSet : ''); + m3_u += '&requestid=' + utils.getUniqueIdentifierStr(); + m3_u += '&impid=' + currentBid.bidId; + m3_u += '&zoneid=' + currentBid.params.zoneid; + m3_u += '&cb=' + Math.floor(Math.random() * 99999999999); + m3_u += document.charset ? '&charset=' + document.charset : (document.characterSet ? '&charset=' + document.characterSet : ''); var loc; try { @@ -39,25 +40,25 @@ var FidelityAdapter = function FidelityAdapter() { }); } - function getFlashVersion(){ + function getFlashVersion() { var plugins, plugin, result; if (navigator.plugins && navigator.plugins.length > 0) { plugins = navigator.plugins; for (var i = 0; i < plugins.length && !result; i++) { plugin = plugins[i]; - if (plugin.name.indexOf("Shockwave Flash") > -1) { - result = plugin.description.split("Shockwave Flash ")[1]; + if (plugin.name.indexOf('Shockwave Flash') > -1) { + result = plugin.description.split('Shockwave Flash ')[1]; } } } - return result ? result : ""; + return result || ''; } function addBlankBidResponses(placementsWithBidsBack) { var allFidelityBidRequests = $$PREBID_GLOBAL$$._bidsRequested.find(bidSet => bidSet.bidderCode === FIDELITY_BIDDER_NAME); - if (allFidelityBidRequests && allFidelityBidRequests.bids){ + if (allFidelityBidRequests && allFidelityBidRequests.bids) { utils._each(allFidelityBidRequests.bids, function (fidelityBid) { if (!utils.contains(placementsWithBidsBack, fidelityBid.placementCode)) { // Add a no-bid response for this placement. @@ -68,11 +69,10 @@ var FidelityAdapter = function FidelityAdapter() { }); } } - - $$PREBID_GLOBAL$$.fidelityResponse = function(responseObj) { + $$PREBID_GLOBAL$$.fidelityResponse = function(responseObj) { if (!responseObj || !responseObj.seatbid || responseObj.seatbid.length === 0 || !responseObj.seatbid[0].bid || responseObj.seatbid[0].bid.length === 0) { - addBlankBidResponses([]); + addBlankBidResponses([]); return; } @@ -97,4 +97,6 @@ var FidelityAdapter = function FidelityAdapter() { }; }; -module.exports = FidelityAdapter; \ No newline at end of file +adaptermanager.registerBidAdapter(new FidelityAdapter(), 'fidelity'); + +module.exports = FidelityAdapter; diff --git a/src/adapters/getintent.js b/modules/getintentBidAdapter.js similarity index 85% rename from src/adapters/getintent.js rename to modules/getintentBidAdapter.js index a98fab952ae..6dc2cb9f4da 100644 --- a/src/adapters/getintent.js +++ b/modules/getintentBidAdapter.js @@ -1,10 +1,9 @@ -/*jshint loopfunc: true */ - import { STATUS } from 'src/constants'; +import adaptermanager from 'src/adaptermanager'; -var bidfactory = require('../bidfactory.js'); -var bidmanager = require('../bidmanager.js'); -var adloader = require('../adloader.js'); +var bidfactory = require('src/bidfactory.js'); +var bidmanager = require('src/bidmanager.js'); +var adloader = require('src/adloader.js'); var GetIntentAdapter = function GetIntentAdapter() { var headerBiddingStaticJS = window.location.protocol + '//cdn.adhigh.net/adserver/hb.js'; @@ -37,7 +36,7 @@ var GetIntentAdapter = function GetIntentAdapter() { known: bidRequest.params.known || 1, is_video: bidRequest.mediaType === 'video', video: bidRequest.params.video || {}, - size: bidRequest.sizes[0].join("x"), + size: bidRequest.sizes[0].join('x'), }; addOptional(bidRequest.params, request, ['cur', 'floor']); (function (r, br) { @@ -71,4 +70,8 @@ var GetIntentAdapter = function GetIntentAdapter() { }; }; +adaptermanager.registerBidAdapter(new GetIntentAdapter(), 'getintent', { + supportedMediaTypes: ['video'] +}); + module.exports = GetIntentAdapter; diff --git a/src/adapters/analytics/ga.js b/modules/googleAnalyticsAdapter.js similarity index 88% rename from src/adapters/analytics/ga.js rename to modules/googleAnalyticsAdapter.js index e17a4832c07..2993697c09d 100644 --- a/src/adapters/analytics/ga.js +++ b/modules/googleAnalyticsAdapter.js @@ -2,9 +2,10 @@ * ga.js - analytics adapter for google analytics */ -var events = require('./../../events'); -var utils = require('./../../utils'); -var CONSTANTS = require('./../../constants.json'); +var events = require('src/events'); +var utils = require('src/utils'); +var CONSTANTS = require('src/constants.json'); +var adaptermanager = require('src/adaptermanager'); var BID_REQUESTED = CONSTANTS.EVENTS.BID_REQUESTED; var BID_TIMEOUT = CONSTANTS.EVENTS.BID_TIMEOUT; @@ -28,10 +29,9 @@ var _sampled = true; * @return {[type]} [description] */ exports.enableAnalytics = function ({ provider, options }) { - _gaGlobal = provider || 'ga'; _trackerSend = options && options.trackerName ? options.trackerName + '.send' : 'send'; - _sampled = typeof options === "undefined" || typeof options.sampling === "undefined" || + _sampled = typeof options === 'undefined' || typeof options.sampling === 'undefined' || Math.random() < parseFloat(options.sampling); if (options && typeof options.global !== 'undefined') { @@ -43,13 +43,13 @@ exports.enableAnalytics = function ({ provider, options }) { var bid = null; - if(_sampled) { - //first send all events fired before enableAnalytics called + if (_sampled) { + // first send all events fired before enableAnalytics called var existingEvents = events.getEvents(); utils._each(existingEvents, function (eventObj) { - if (typeof eventObj !== "object") { + if (typeof eventObj !== 'object') { return; } var args = eventObj.args; @@ -58,10 +58,9 @@ exports.enableAnalytics = function ({ provider, options }) { bid = args; sendBidRequestToGa(bid); } else if (eventObj.eventType === BID_RESPONSE) { - //bid is 2nd args + // bid is 2nd args bid = args; sendBidResponseToGa(bid); - } else if (eventObj.eventType === BID_TIMEOUT) { const bidderArray = args; sendBidTimeouts(bidderArray); @@ -71,30 +70,29 @@ exports.enableAnalytics = function ({ provider, options }) { } }); - //Next register event listeners to send data immediately + // Next register event listeners to send data immediately - //bidRequests + // bidRequests events.on(BID_REQUESTED, function (bidRequestObj) { sendBidRequestToGa(bidRequestObj); }); - //bidResponses + // bidResponses events.on(BID_RESPONSE, function (bid) { sendBidResponseToGa(bid); }); - //bidTimeouts + // bidTimeouts events.on(BID_TIMEOUT, function (bidderArray) { sendBidTimeouts(bidderArray); }); - //wins + // wins events.on(BID_WON, function (bid) { sendBidWonToGa(bid); }); - } else { - utils.logMessage("Prebid.js google analytics disabled by sampling"); + utils.logMessage('Prebid.js google analytics disabled by sampling'); } // finally set this function to return log message, prevents multiple adapter listeners @@ -112,17 +110,16 @@ exports.getTrackerSend = function getTrackerSend() { */ function checkAnalytics() { if (_enableCheck && typeof window[_gaGlobal] === 'function') { - for (var i = 0; i < _analyticsQueue.length; i++) { _analyticsQueue[i].call(); } - //override push to execute the command immediately from now on + // override push to execute the command immediately from now on _analyticsQueue.push = function (fn) { fn.call(); }; - //turn check into NOOP + // turn check into NOOP _enableCheck = false; } @@ -201,12 +198,11 @@ function sendBidRequestToGa(bid) { }); } - //check the queue + // check the queue checkAnalytics(); } function sendBidResponseToGa(bid) { - if (bid && bid.bidderCode) { _analyticsQueue.push(function () { var cpmCents = convertToCents(bid.cpm); @@ -231,12 +227,11 @@ function sendBidResponseToGa(bid) { }); } - //check the queue + // check the queue checkAnalytics(); } function sendBidTimeouts(timedOutBidders) { - _analyticsQueue.push(function () { utils._each(timedOutBidders, function (bidderCode) { _eventCount++; @@ -256,3 +251,8 @@ function sendBidWonToGa(bid) { checkAnalytics(); } + +adaptermanager.registerAnalyticsAdapter({ + adapter: exports, + code: 'ga' +}); diff --git a/src/adapters/gumgum.js b/modules/gumgumBidAdapter.js similarity index 66% rename from src/adapters/gumgum.js rename to modules/gumgumBidAdapter.js index d9a08d96b97..7aff53fbcc6 100644 --- a/src/adapters/gumgum.js +++ b/modules/gumgumBidAdapter.js @@ -1,13 +1,13 @@ -const bidfactory = require('../bidfactory'); -const bidmanager = require('../bidmanager'); -const utils = require('../utils'); -const adloader = require('../adloader'); +const bidfactory = require('src/bidfactory'); +const bidmanager = require('src/bidmanager'); +const utils = require('src/utils'); +const adloader = require('src/adloader'); +var adaptermanager = require('src/adaptermanager'); const BIDDER_CODE = 'gumgum'; const CALLBACKS = {}; const GumgumAdapter = function GumgumAdapter() { - const bidEndpoint = `https://g2.gumgum.com/hbid/imp`; let topWindow; @@ -16,6 +16,7 @@ const GumgumAdapter = function GumgumAdapter() { const requestCache = {}; const throttleTable = {}; const defaultThrottle = 3e4; + const dtCredentials = { member: 'YcXr87z2lpbB' }; try { topWindow = global.top; @@ -28,6 +29,22 @@ const GumgumAdapter = function GumgumAdapter() { return new Date().getTime(); } + function _getDigiTrustQueryParams() { + function getDigiTrustId () { + var digiTrustUser = (window.DigiTrust && window.DigiTrust.getUser) ? window.DigiTrust.getUser(dtCredentials) : {}; + return digiTrustUser && digiTrustUser.success && digiTrustUser.identity || ''; + }; + + let digiTrustId = getDigiTrustId(); + // Verify there is an ID and this user has not opted out + if (!digiTrustId || digiTrustId.privacy && digiTrustId.privacy.optout) { + return {}; + } + return { + 'dt': digiTrustId.id + }; + } + function _callBids({ bids }) { const browserParams = { vw: topWindow.innerWidth, @@ -38,23 +55,24 @@ const GumgumAdapter = function GumgumAdapter() { ce: navigator.cookieEnabled, dpr: topWindow.devicePixelRatio || 1 }; + utils._each(bids, bidRequest => { const { bidId - , params = {} - , placementCode - } = bidRequest; - const timestamp = _getTimeStamp(); + , params = {} + , placementCode + } = bidRequest; + const timestamp = _getTimeStamp(); const trackingId = params.inScreen; - const nativeId = params.native; - const slotId = params.inSlot; - const bid = { tmax: $$PREBID_GLOBAL$$.cbTimeout }; + const nativeId = params.native; + const slotId = params.inSlot; + const bid = { tmax: $$PREBID_GLOBAL$$.cbTimeout }; /* slot/native ads need the placement id */ switch (true) { - case !!(params.inImage): bid.pi = 1; break; + case !!(params.inImage): bid.pi = 1; break; case !!(params.inScreen): bid.pi = 2; break; - case !!(params.inSlot): bid.pi = 3; break; - case !!(params.native): bid.pi = 5; break; + case !!(params.inSlot): bid.pi = 3; break; + case !!(params.native): bid.pi = 5; break; default: return utils.logWarn( `[GumGum] No product selected for the placement ${placementCode}` + ', please check your implementation.' @@ -62,14 +80,14 @@ const GumgumAdapter = function GumgumAdapter() { } /* throttle based on the latest request for this product */ - const productId = bid.pi; - const requestKey = productId + '|' + placementCode; - const throttle = throttleTable[productId]; + const productId = bid.pi; + const requestKey = productId + '|' + placementCode; + const throttle = throttleTable[productId]; const latestRequest = requestCache[requestKey]; if (latestRequest && throttle && (timestamp - latestRequest) < throttle) { return utils.logWarn( - `[GumGum] The refreshes for "${ placementCode }" with the params ` + - `${ JSON.stringify(params) } should be at least ${ throttle / 1e3 }s apart.` + `[GumGum] The refreshes for "${placementCode}" with the params ` + + `${JSON.stringify(params)} should be at least ${throttle / 1e3}s apart.` ); } /* update the last request */ @@ -90,9 +108,9 @@ const GumgumAdapter = function GumgumAdapter() { id: bidId }, bid); - const callback = { jsonp: `$$PREBID_GLOBAL$$.handleGumGumCB['${ bidId }']` }; + const callback = { jsonp: `$$PREBID_GLOBAL$$.handleGumGumCB['${bidId}']` }; CALLBACKS[bidId] = _handleGumGumResponse(cachedBid); - const query = Object.assign(callback, browserParams, bid); + const query = Object.assign(callback, browserParams, bid, _getDigiTrustQueryParams()); const bidCall = `${bidEndpoint}?${utils.parseQueryStringParameters(query)}`; adloader.loadScript(bidCall); }); @@ -100,11 +118,11 @@ const GumgumAdapter = function GumgumAdapter() { const _handleGumGumResponse = cachedBidRequest => (bidResponse = {}) => { const { pi: productId - } = cachedBidRequest; + } = cachedBidRequest; const { ad = {} - , pag = {} - , thms: throttle - } = bidResponse; + , pag = {} + , thms: throttle + } = bidResponse; /* cache the pageViewId */ if (pag && pag.pvid) pageViewId = pag.pvid; if (ad && ad.id) { @@ -113,7 +131,7 @@ const GumgumAdapter = function GumgumAdapter() { /* create the bid */ const bid = bidfactory.createBid(1); const { t: trackingId - } = pag; + } = pag; bidResponse.request = cachedBidRequest; const encodedResponse = encodeURIComponent(JSON.stringify(bidResponse)); const gumgumAdLoader = ``; } @@ -161,4 +161,6 @@ const LifestreetAdapter = function LifestreetAdapter() { }; }; -module.exports = LifestreetAdapter; \ No newline at end of file +adaptermanager.registerBidAdapter(new LifestreetAdapter(), 'lifestreet'); + +module.exports = LifestreetAdapter; diff --git a/src/adapters/mantis.js b/modules/mantisBidAdapter.js similarity index 90% rename from src/adapters/mantis.js rename to modules/mantisBidAdapter.js index 6ca3faa0bca..4dfb62f395b 100644 --- a/src/adapters/mantis.js +++ b/modules/mantisBidAdapter.js @@ -1,9 +1,10 @@ -var bidfactory = require('../bidfactory.js'); -var bidmanager = require('../bidmanager.js'); -var adloader = require('../adloader'); -var constants = require('../constants.json'); +var bidfactory = require('src/bidfactory.js'); +var bidmanager = require('src/bidmanager.js'); +var adloader = require('src/adloader'); +var constants = require('src/constants.json'); +var adaptermanager = require('src/adaptermanager'); -module.exports = function () { +function MantisAdapter () { function inIframe() { try { return window.self !== window.top && !window.mantis_link; @@ -51,11 +52,11 @@ module.exports = function () { } function isAmp() { - return typeof window.context === "object" && (window.context.tagName === "AMP-AD" || window.context.tagName === "AMP-EMBED"); + return typeof window.context === 'object' && (window.context.tagName === 'AMP-AD' || window.context.tagName === 'AMP-EMBED'); } function isSecure() { - return document.location.protocol === "https:"; + return document.location.protocol === 'https:'; } function isArray(value) { @@ -109,7 +110,6 @@ module.exports = function () { return parts.join('&'); } - function buildMantisUrl(path, data, domain) { var params = { referrer: document.referrer, @@ -221,4 +221,8 @@ module.exports = function () { }; return new Prebid(bidfactory, bidmanager, adloader, constants); -}; \ No newline at end of file +} + +adaptermanager.registerBidAdapter(new MantisAdapter(), 'mantis'); + +module.exports = MantisAdapter; diff --git a/src/adapters/memeglobal.js b/modules/memeglobalBidAdapter.js similarity index 91% rename from src/adapters/memeglobal.js rename to modules/memeglobalBidAdapter.js index 9eb7f297d97..40bb5b367b2 100644 --- a/src/adapters/memeglobal.js +++ b/modules/memeglobalBidAdapter.js @@ -1,8 +1,9 @@ -var CONSTANTS = require('../constants.json'); -var utils = require('../utils.js'); -var bidfactory = require('../bidfactory.js'); -var bidmanager = require('../bidmanager.js'); -var adloader = require('../adloader'); +var CONSTANTS = require('src/constants.json'); +var utils = require('src/utils.js'); +var bidfactory = require('src/bidfactory.js'); +var bidmanager = require('src/bidmanager.js'); +var adloader = require('src/adloader'); +var adaptermanager = require('src/adaptermanager'); var defaultPlacementForBadBid = null; var bidderName = 'memeglobal'; @@ -79,11 +80,10 @@ var MemeGlobalAdapter = function MemeGlobalAdapter() { // expose the callback to the global object: $$PREBID_GLOBAL$$.mgres = function (bidResp) { - // valid object? if ((!bidResp || !bidResp.id) || (!bidResp.seatbid || bidResp.seatbid.length === 0 || !bidResp.seatbid[0].bid || bidResp.seatbid[0].bid.length === 0)) { - return ; + return; } bidResp.seatbid[0].bid.forEach(function (bidderBid) { @@ -123,4 +123,6 @@ var MemeGlobalAdapter = function MemeGlobalAdapter() { }; }; +adaptermanager.registerBidAdapter(new MemeGlobalAdapter(), 'memeglobal'); + module.exports = MemeGlobalAdapter; diff --git a/src/adapters/nginad.js b/modules/nginadBidAdapter.js similarity index 85% rename from src/adapters/nginad.js rename to modules/nginadBidAdapter.js index 8488fa513cb..32560120d64 100644 --- a/src/adapters/nginad.js +++ b/modules/nginadBidAdapter.js @@ -1,8 +1,9 @@ -var CONSTANTS = require('../constants.json'); -var utils = require('../utils.js'); -var bidfactory = require('../bidfactory.js'); -var bidmanager = require('../bidmanager.js'); -var adloader = require('../adloader'); +var CONSTANTS = require('src/constants.json'); +var utils = require('src/utils.js'); +var bidfactory = require('src/bidfactory.js'); +var bidmanager = require('src/bidmanager.js'); +var adloader = require('src/adloader'); +var adaptermanager = require('src/adaptermanager'); var defaultPlacementForBadBid = null; @@ -10,7 +11,6 @@ var defaultPlacementForBadBid = null; * Adapter for requesting bids from NginAd */ var NginAdAdapter = function NginAdAdapter() { - var rtbServerDomain = 'placeholder.for.nginad.server.com'; function _callBids(params) { @@ -40,7 +40,6 @@ var NginAdAdapter = function NginAdAdapter() { } function getWidthAndHeight(bid) { - var adW = null; var adH = null; @@ -63,11 +62,10 @@ var NginAdAdapter = function NginAdAdapter() { var nginadImps = []; - //assign the first adUnit (placement) for bad bids; + // assign the first adUnit (placement) for bad bids; defaultPlacementForBadBid = bidReqs[0].placementCode; - - //build impression array for nginad + // build impression array for nginad utils._each(bidReqs, function(bid) { var tagId = utils.getBidIdParameter('pzoneid', bid.params); var bidFloor = utils.getBidIdParameter('bidfloor', bid.params); @@ -85,10 +83,9 @@ var NginAdAdapter = function NginAdAdapter() { }; nginadImps.push(imp); - //bidmanager.pbCallbackMap[imp.id] = bid; + // bidmanager.pbCallbackMap[imp.id] = bid; rtbServerDomain = bid.params.nginadDomain; - }); // build bid request with impressions @@ -108,7 +105,7 @@ var NginAdAdapter = function NginAdAdapter() { } function handleErrorResponse(bidReqs, defaultPlacementForBadBid) { - //no response data + // no response data if (defaultPlacementForBadBid === null) { // no id with which to create an dummy bid return; @@ -119,7 +116,7 @@ var NginAdAdapter = function NginAdAdapter() { bidmanager.addBidResponse(defaultPlacementForBadBid, bid); } - //expose the callback to the global object: + // expose the callback to the global object: $$PREBID_GLOBAL$$.nginadResponse = function(nginadResponseObj) { var bid = {}; var key; @@ -134,7 +131,6 @@ var NginAdAdapter = function NginAdAdapter() { } for (key in nginadResponseObj.seatbid[0].bid) { - var nginadBid = nginadResponseObj.seatbid[0].bid[key]; var responseCPM; @@ -142,7 +138,6 @@ var NginAdAdapter = function NginAdAdapter() { var id = nginadBid.impid; // try to fetch the bid request we sent NginAd - /*jshint -W083 */ var bidObj = $$PREBID_GLOBAL$$._bidsRequested.find(bidSet => bidSet.bidderCode === 'nginad').bids .find(bid => bid.bidId === id); if (!bidObj) { @@ -152,7 +147,7 @@ var NginAdAdapter = function NginAdAdapter() { placementCode = bidObj.placementCode; bidObj.status = CONSTANTS.STATUS.GOOD; - //place ad response on bidmanager._adResponsesByBidderId + // place ad response on bidmanager._adResponsesByBidderId responseCPM = parseFloat(nginadBid.price); if (responseCPM === 0) { @@ -163,14 +158,14 @@ var NginAdAdapter = function NginAdAdapter() { nginadBid.size = bidObj.sizes; var responseAd = nginadBid.adm; - //store bid response - //bid status is good (indicating 1) + // store bid response + // bid status is good (indicating 1) bid = bidfactory.createBid(1); bid.creative_id = nginadBid.Id; bid.bidderCode = 'nginad'; bid.cpm = responseCPM; - //The bid is a mock bid, the true bidding process happens after the publisher tag is called + // The bid is a mock bid, the true bidding process happens after the publisher tag is called bid.ad = decodeURIComponent(responseAd); var whArr = getWidthAndHeight(bidObj); @@ -178,9 +173,7 @@ var NginAdAdapter = function NginAdAdapter() { bid.height = whArr[1]; bidmanager.addBidResponse(placementCode, bid); - } - }; // nginadResponse return { @@ -188,4 +181,6 @@ var NginAdAdapter = function NginAdAdapter() { }; }; +adaptermanager.registerBidAdapter(new NginAdAdapter(), 'nginad'); + module.exports = NginAdAdapter; diff --git a/src/adapters/openx.js b/modules/openxBidAdapter.js similarity index 90% rename from src/adapters/openx.js rename to modules/openxBidAdapter.js index 42314e7f286..19093c2295e 100644 --- a/src/adapters/openx.js +++ b/modules/openxBidAdapter.js @@ -1,8 +1,9 @@ -const bidfactory = require('../bidfactory.js'); -const bidmanager = require('../bidmanager.js'); -const adloader = require('../adloader'); -const CONSTANTS = require('../constants.json'); -const utils = require('../utils.js'); +const bidfactory = require('src/bidfactory.js'); +const bidmanager = require('src/bidmanager.js'); +const adloader = require('src/adloader'); +const CONSTANTS = require('src/constants.json'); +const utils = require('src/utils.js'); +const adaptermanager = require('src/adaptermanager'); const OpenxAdapter = function OpenxAdapter() { const BIDDER_CODE = 'openx'; @@ -29,7 +30,7 @@ const OpenxAdapter = function OpenxAdapter() { // find the adunit in the response for (let j = 0; j < adUnits.length; j++) { adUnit = adUnits[j]; - if (String(bid.params.unit) === String(adUnit.adunitid) && adUnitHasValidSizeFromBid(adUnit,bid) && !adUnit.used) { + if (String(bid.params.unit) === String(adUnit.adunitid) && adUnitHasValidSizeFromBid(adUnit, bid) && !adUnit.used) { auid = adUnit.adunitid; break; } @@ -38,7 +39,7 @@ const OpenxAdapter = function OpenxAdapter() { let beaconParams = { bd: +(new Date()) - startTime, br: '0', // maybe 0, t, or p - bt: $$PREBID_GLOBAL$$.cbTimeout || $$PREBID_GLOBAL$$.bidderTimeout , // For the timeout per bid request + bt: $$PREBID_GLOBAL$$.cbTimeout || $$PREBID_GLOBAL$$.bidderTimeout, // For the timeout per bid request bs: window.location.hostname }; @@ -69,8 +70,7 @@ const OpenxAdapter = function OpenxAdapter() { try { tWin = window.top; tDoc = window.top.document; - } - catch (e) { + } catch (e) { return; } docEl = tDoc.documentElement; @@ -90,8 +90,8 @@ const OpenxAdapter = function OpenxAdapter() { function makePDCall(pixelsUrl) { let pdFrame = utils.createInvisibleIframe(); let name = 'openx-pd'; - pdFrame.setAttribute("id", name); - pdFrame.setAttribute("name", name); + pdFrame.setAttribute('id', name); + pdFrame.setAttribute('name', name); let rootNode = document.body; if (!rootNode) { @@ -182,7 +182,7 @@ const OpenxAdapter = function OpenxAdapter() { bids.forEach(function (bid) { for (let customParam in bid.params.customParams) { if (bid.params.customParams.hasOwnProperty(customParam)) { - params["c." + customParam] = bid.params.customParams[customParam]; + params['c.' + customParam] = bid.params.customParams[customParam]; } } }); @@ -200,8 +200,7 @@ const OpenxAdapter = function OpenxAdapter() { currentURL = currentURL && encodeURIComponent(currentURL); try { isIfr = window.self !== window.top; - } - catch (e) { + } catch (e) { isIfr = false; } if (bids.length === 0) { @@ -220,12 +219,11 @@ const OpenxAdapter = function OpenxAdapter() { ifr: isIfr, tz: startTime.getTimezoneOffset(), tws: getViewportDimensions(isIfr), - ee: 'api_sync_write', ef: 'bt%2Cdb', be: 1, bc: BIDDER_CONFIG }, - delDomain); + delDomain); } return { @@ -233,4 +231,6 @@ const OpenxAdapter = function OpenxAdapter() { }; }; +adaptermanager.registerBidAdapter(new OpenxAdapter(), 'openx'); + module.exports = OpenxAdapter; diff --git a/src/adapters/piximedia.js b/modules/piximediaBidAdapter.js similarity index 83% rename from src/adapters/piximedia.js rename to modules/piximediaBidAdapter.js index f0d9c1e8143..3da31968530 100644 --- a/src/adapters/piximedia.js +++ b/modules/piximediaBidAdapter.js @@ -1,9 +1,10 @@ -var CONSTANTS = require('../constants.json'); -var utils = require('../utils.js'); -var bidmanager = require('../bidmanager.js'); -var bidfactory = require('../bidfactory.js'); -var adloader = require('../adloader.js'); -var Adapter = require('./adapter.js'); +var CONSTANTS = require('src/constants.json'); +var utils = require('src/utils.js'); +var bidmanager = require('src/bidmanager.js'); +var bidfactory = require('src/bidfactory.js'); +var adloader = require('src/adloader.js'); +var Adapter = require('src/adapter.js'); +var adaptermanager = require('src/adaptermanager'); var PiximediaAdapter = function PiximediaAdapter() { var PREBID_URL = '//static.adserver.pm/prebid'; @@ -11,16 +12,14 @@ var PiximediaAdapter = function PiximediaAdapter() { var bidStash = {}; var tryAppendPixiQueryString = function(url, name, value) { - return url + "/" + encodeURIComponent(name) + "=" + value; + return url + '/' + encodeURIComponent(name) + '=' + value; }; baseAdapter.callBids = function callBidsPiximedia(params) { utils._each(params.bids, function(bid) { - // valid bids must include a siteId and an placementId if (bid.placementCode && bid.sizes && bid.params && bid.params.siteId && bid.params.placementId) { - - var sizes = bid.params.hasOwnProperty('sizes')? bid.params.sizes: bid.sizes; + var sizes = bid.params.hasOwnProperty('sizes') ? bid.params.sizes : bid.sizes; sizes = utils.parseSizesInput(sizes); var cbid = utils.getUniqueIdentifierStr(); @@ -29,32 +28,32 @@ var PiximediaAdapter = function PiximediaAdapter() { var url = bid.params.prebidUrl || PREBID_URL; // params are passed to the Piximedia endpoint, including custom params - for(var key in bid.params) { + for (var key in bid.params) { /* istanbul ignore else */ - if(bid.params.hasOwnProperty(key)) { + if (bid.params.hasOwnProperty(key)) { var value = bid.params[key]; - switch(key) { - case "siteId": + switch (key) { + case 'siteId': url = tryAppendPixiQueryString(url, 'site_id', encodeURIComponent(value)); break; - case "placementId": + case 'placementId': url = tryAppendPixiQueryString(url, 'placement_id', encodeURIComponent(value)); break; - case "dealId": + case 'dealId': url = tryAppendPixiQueryString(url, 'l_id', encodeURIComponent(value)); break; - case "sizes": - case "prebidUrl": + case 'sizes': + case 'prebidUrl': break; default: - if(typeof value === "function") { - url = tryAppendPixiQueryString(url, key, encodeURIComponent((value(baseAdapter, params, bid) || "").toString())); + if (typeof value === 'function') { + url = tryAppendPixiQueryString(url, key, encodeURIComponent((value(baseAdapter, params, bid) || '').toString())); } else { - url = tryAppendPixiQueryString(url, key, encodeURIComponent((value || "").toString())); + url = tryAppendPixiQueryString(url, key, encodeURIComponent((value || '').toString())); } break; } @@ -62,7 +61,7 @@ var PiximediaAdapter = function PiximediaAdapter() { } url = tryAppendPixiQueryString(url, 'jsonp', '$$PREBID_GLOBAL$$.handlePiximediaCallback'); - url = tryAppendPixiQueryString(url, 'sizes', encodeURIComponent(sizes.join(","))); + url = tryAppendPixiQueryString(url, 'sizes', encodeURIComponent(sizes.join(','))); url = tryAppendPixiQueryString(url, 'cbid', encodeURIComponent(cbid)); url = tryAppendPixiQueryString(url, 'rand', String(Math.floor(Math.random() * 1000000000))); @@ -92,7 +91,7 @@ var PiximediaAdapter = function PiximediaAdapter() { * */ $$PREBID_GLOBAL$$.handlePiximediaCallback = function(bidResponse) { - if (bidResponse && bidResponse.hasOwnProperty("foundbypm")) { + if (bidResponse && bidResponse.hasOwnProperty('foundbypm')) { var stash = bidStash[bidResponse.cbid]; // retrieve our stashed data, by using the cbid var bid; @@ -102,7 +101,6 @@ var PiximediaAdapter = function PiximediaAdapter() { timelapsed = timelapsed - stash.start; if (bidResponse.foundbypm && bidResponse.width && bidResponse.height && bidResponse.html && bidResponse.cpm && bidResponse.currency) { - /* we have a valid ad to display */ bid = bidfactory.createBid(CONSTANTS.STATUS.GOOD); bid.bidderCode = bidObj.bidder; @@ -126,7 +124,6 @@ var PiximediaAdapter = function PiximediaAdapter() { ' CPM: ' + String(bid.cpm) + ' ' + bid.currency + ' Format: ' + String(bid.width) + 'x' + String(bid.height)); } else { - /* we have no ads to display */ bid = bidfactory.createBid(CONSTANTS.STATUS.NO_BID); bid.bidderCode = bidObj.bidder; @@ -139,7 +136,6 @@ var PiximediaAdapter = function PiximediaAdapter() { // We should no longer need this stashed object, so drop reference: bidStash[bidResponse.cbid] = null; - } else { utils.logMessage("[Piximedia] Couldn't find stash for cbid=" + bidResponse.cbid); } @@ -154,4 +150,6 @@ var PiximediaAdapter = function PiximediaAdapter() { }; }; +adaptermanager.registerBidAdapter(new PiximediaAdapter(), 'piximedia'); + module.exports = PiximediaAdapter; diff --git a/modules/prebidServerBidAdapter.js b/modules/prebidServerBidAdapter.js new file mode 100644 index 00000000000..775a81b0d6e --- /dev/null +++ b/modules/prebidServerBidAdapter.js @@ -0,0 +1,217 @@ +import Adapter from 'src/adapter'; +import bidfactory from 'src/bidfactory'; +import bidmanager from 'src/bidmanager'; +import * as utils from 'src/utils'; +import { ajax } from 'src/ajax'; +import { STATUS, S2S } from 'src/constants'; +import { queueSync, cookieSet } from 'src/cookie'; +import adaptermanager from 'src/adaptermanager'; + +const TYPE = S2S.SRC; +const cookieSetUrl = 'https://acdn.adnxs.com/cookieset/cs.js'; + +const paramTypes = { + 'appnexus': { + 'member': 'string', + 'invCode': 'string', + 'placementId': 'number' + }, + 'rubicon': { + 'accountId': 'number', + 'siteId': 'number', + 'zoneId': 'number' + }, + 'indexExchange': { + 'siteID': 'number' + }, + 'audienceNetwork': { + 'placementId': 'string' + }, + 'pubmatic': { + 'publisherId': 'string', + 'adSlot': 'string' + } +}; + +let _cookiesQueued = false; + +/** + * Bidder adapter for Prebid Server + */ +function PrebidServer() { + let baseAdapter = Adapter.createNew('prebidServer'); + let config; + + baseAdapter.setConfig = function(s2sconfig) { + config = s2sconfig; + }; + + function convertTypes(adUnits) { + adUnits.forEach(adUnit => { + adUnit.bids.forEach(bid => { + const types = paramTypes[bid.bidder] || []; + Object.keys(types).forEach(key => { + if (bid.params[key] && typeof bid.params[key] !== types[key]) { + // mismatch type. Try to fix + utils.logMessage(`Mismatched type for Prebid Server : ${bid.bidder} : ${key}. Required Type:${types[key]}`); + bid.params[key] = tryConvertType(types[key], bid.params[key]); + // don't send invalid values + if (isNaN(bid.params[key])) { + delete bid.params.key; + } + } + }); + }); + }); + } + + function tryConvertType(typeToConvert, value) { + if (typeToConvert === 'string') { + return value && value.toString(); + } + if (typeToConvert === 'number') { + return Number(value); + } + } + + /* Prebid executes this function when the page asks to send out bid requests */ + baseAdapter.callBids = function(bidRequest) { + const isDebug = !!$$PREBID_GLOBAL$$.logging; + convertTypes(bidRequest.ad_units); + let requestJson = { + account_id: config.accountId, + tid: bidRequest.tid, + max_bids: config.maxBids, + timeout_millis: config.timeout, + url: utils.getTopWindowUrl(), + prebid_version: '$prebid.version$', + ad_units: bidRequest.ad_units.filter(hasSizes), + is_debug: isDebug + }; + + const payload = JSON.stringify(requestJson); + ajax(config.endpoint, handleResponse, payload, { + contentType: 'text/plain', + withCredentials: true + }); + }; + + // at this point ad units should have a size array either directly or mapped so filter for that + function hasSizes(unit) { + return unit.sizes && unit.sizes.length; + } + + /* Notify Prebid of bid responses so bids can get in the auction */ + function handleResponse(response) { + let result; + try { + result = JSON.parse(response); + + if (result.status === 'OK' || result.status === 'no_cookie') { + if (result.bidder_status) { + result.bidder_status.forEach(bidder => { + if (bidder.no_cookie && !_cookiesQueued) { + queueSync({bidder: bidder.bidder, url: bidder.usersync.url, type: bidder.usersync.type}); + } + }); + } + + if (result.bids) { + result.bids.forEach(bidObj => { + let bidRequest = utils.getBidRequest(bidObj.bid_id); + let cpm = bidObj.price; + let status; + if (cpm !== 0) { + status = STATUS.GOOD; + } else { + status = STATUS.NO_BID; + } + + let bidObject = bidfactory.createBid(status, bidRequest); + bidObject.source = TYPE; + bidObject.creative_id = bidObj.creative_id; + bidObject.bidderCode = bidObj.bidder; + bidObject.cpm = cpm; + bidObject.ad = bidObj.adm; + bidObject.width = bidObj.width; + bidObject.height = bidObj.height; + if (bidObj.deal_id) { + bidObject.dealId = bidObj.deal_id; + } + + bidmanager.addBidResponse(bidObj.code, bidObject); + }); + } + + const receivedBidIds = result.bids ? result.bids.map(bidObj => bidObj.bid_id) : []; + + // issue a no-bid response for every bid request that can not be matched with received bids + config.bidders.forEach(bidder => { + utils + .getBidderRequestAllAdUnits(bidder) + .bids.filter(bidRequest => !receivedBidIds.includes(bidRequest.bidId)) + .forEach(bidRequest => { + let bidObject = bidfactory.createBid(STATUS.NO_BID, bidRequest); + bidObject.source = TYPE; + bidObject.adUnitCode = bidRequest.placementCode; + bidObject.bidderCode = bidRequest.bidder; + + bidmanager.addBidResponse(bidObject.adUnitCode, bidObject); + }); + }); + } + if (result.status === 'no_cookie' && config.cookieSet) { + // cookie sync + cookieSet(cookieSetUrl); + } + } catch (error) { + utils.logError(error); + } + + if (!result || result.status && result.status.includes('Error')) { + utils.logError('error parsing response: ', result.status); + } + } + /** + * @param {} {bidders} list of bidders to request user syncs for. + */ + baseAdapter.queueSync = function({bidderCodes}) { + if (!_cookiesQueued) { + _cookiesQueued = true; + const payload = JSON.stringify({ + uuid: utils.generateUUID(), + bidders: bidderCodes + }); + ajax(config.syncEndpoint, (response) => { + try { + response = JSON.parse(response); + response.bidder_status.forEach(bidder => queueSync({bidder: bidder.bidder, url: bidder.usersync.url, type: bidder.usersync.type})); + } + catch (e) { + utils.logError(e); + } + }, + payload, { + contentType: 'text/plain', + withCredentials: true + }); + } + } + + return { + queueSync: baseAdapter.queueSync, + setConfig: baseAdapter.setConfig, + createNew: PrebidServer.createNew, + callBids: baseAdapter.callBids, + setBidderCode: baseAdapter.setBidderCode, + type: TYPE + }; +} + +PrebidServer.createNew = function() { + return new PrebidServer(); +}; + +adaptermanager.registerBidAdapter(new PrebidServer(), 'prebidServer'); + +module.exports = PrebidServer; diff --git a/src/adapters/pubgears.js b/modules/pubgearsBidAdapter.js similarity index 88% rename from src/adapters/pubgears.js rename to modules/pubgearsBidAdapter.js index 6d487826a75..0bd1d250077 100644 --- a/src/adapters/pubgears.js +++ b/modules/pubgearsBidAdapter.js @@ -1,7 +1,8 @@ -var bidfactory = require('../bidfactory.js'); -var bidmanager = require('../bidmanager.js'); -var consts = require('../constants.json'); -var utils = require('../utils.js'); +var bidfactory = require('src/bidfactory.js'); +var bidmanager = require('src/bidmanager.js'); +var consts = require('src/constants.json'); +var utils = require('src/utils.js'); +var adaptermanager = require('src/adaptermanager'); var d = document; var SCRIPT = 'script'; var PARAMS = 'params'; @@ -32,6 +33,8 @@ var CREATIVE_TEMPLATE = decodeURIComponent("%3Cscript%3E%0A(function(define)%7B% var TAG_URL = '//c.pubgears.com/tags/h'; var publisher = ''; +adaptermanager.registerBidAdapter(new PubGearsAdapter(), BIDDER_CODE); + module.exports = PubGearsAdapter; function PubGearsAdapter() { @@ -43,20 +46,19 @@ function PubGearsAdapter() { function callBids(params) { var bids = params[consts.JSON_MAPPING.PL_BIDS]; - var slots = bids.map(getSlotFromBidParam) ; - if(slots.length <= 0) - return; + var slots = bids.map(getSlotFromBidParam); + if (slots.length <= 0) + { return; } publisher = bids[0][PARAMS][PUBLISHER_PARAM]; bids.forEach(function(bid) { - var name = getSlotFromBidParam(bid); pendingSlots[ name ] = bid; }); proxy = proxy || getScript(SCRIPT_ID) || makeScript(slots, publisher, SCRIPT_ID, TAG_URL); - if(!initialized) - registerEventListeners(proxy); + if (!initialized) + { registerEventListeners(proxy); } initialized = true; } function loadScript(script) { @@ -74,7 +76,7 @@ function PubGearsAdapter() { } function getSlotFromResource(resource) { var size = resource[SIZE]; - var key = [ resource[PUB_ZONE], size ].join('@'); + var key = [ resource[PUB_ZONE], size ].join('@'); return key; } function getSize(bid) { @@ -85,7 +87,7 @@ function PubGearsAdapter() { function makeScript(slots, publisher, id, url) { var script = d.createElement(SCRIPT); script.src = url; - script.id = id ; + script.id = id; script.setAttribute(ATTRIBUTE_PREFIX + SLOT_LIST_ATTRIBUTE, slots.join(' ')); script.setAttribute(ATTRIBUTE_PREFIX + FLAG_ATTRIBUTE, 'true'); script.setAttribute(ATTRIBUTE_PREFIX + PUBLISHER_ATTRIBUTE, publisher); @@ -106,11 +108,11 @@ function PubGearsAdapter() { var adUnitCode = bidRequest[PLACEMENT_CODE]; var bid = null; - if(bidRequest) { + if (bidRequest) { bid = buildResponse(data, bidRequest); bidmanager.addBidResponse(adUnitCode, bid); utils.logMessage('adding bid respoonse to "' + adUnitCode + '" for bid request "' + bidRequest[BID_ID] + '"'); - }else { + } else { utils.logError('Cannot get placement id for slot "' + slotKey + '"'); } } @@ -123,12 +125,12 @@ function PubGearsAdapter() { var response = bidfactory.createBid(status, bidRequest); response[BIDDER_CODE_RESPONSE_KEY] = BIDDER_CODE; - if(status !== 1) - return response; + if (status !== 1) + { return response; } response[AD] = getCreative(resource); - response[CPM] = price / 1e3 ; + response[CPM] = price / 1e3; response[WIDTH] = dims[0]; response[HEIGHT] = dims[1]; return response; diff --git a/src/adapters/pubmatic.js b/modules/pubmaticBidAdapter.js similarity index 81% rename from src/adapters/pubmatic.js rename to modules/pubmaticBidAdapter.js index 3f0a54be2cb..1517a53eee1 100644 --- a/src/adapters/pubmatic.js +++ b/modules/pubmaticBidAdapter.js @@ -1,6 +1,7 @@ -var utils = require('../utils.js'); -var bidfactory = require('../bidfactory.js'); -var bidmanager = require('../bidmanager.js'); +var utils = require('src/utils.js'); +var bidfactory = require('src/bidfactory.js'); +var bidmanager = require('src/bidmanager.js'); +var adaptermanager = require('src/adaptermanager'); /** * Adapter for requesting bids from Pubmatic. @@ -8,10 +9,12 @@ var bidmanager = require('../bidmanager.js'); * @returns {{callBids: _callBids}} * @constructor */ -var PubmaticAdapter = function PubmaticAdapter() { - +function PubmaticAdapter() { var bids; var _pm_pub_id; + var _pm_pub_age; + var _pm_pub_gender; + var _pm_pub_kvs; var _pm_optimize_adslots = []; let iframe; @@ -20,8 +23,11 @@ var PubmaticAdapter = function PubmaticAdapter() { _pm_optimize_adslots = []; for (var i = 0; i < bids.length; i++) { var bid = bids[i]; - //bidmanager.pbCallbackMap['' + bid.params.adSlot] = bid; + // bidmanager.pbCallbackMap['' + bid.params.adSlot] = bid; _pm_pub_id = _pm_pub_id || bid.params.publisherId; + _pm_pub_age = _pm_pub_age || (bid.params.age || ''); + _pm_pub_gender = _pm_pub_gender || (bid.params.gender || ''); + _pm_pub_kvs = _pm_pub_kvs || (bid.params.kvs || ''); _pm_optimize_adslots.push(bid.params.adSlot); } @@ -30,14 +36,12 @@ var PubmaticAdapter = function PubmaticAdapter() { } function _getBids() { - - - //create the iframe + // create the iframe iframe = utils.createInvisibleIframe(); var elToAppend = document.getElementsByTagName('head')[0]; - //insert the iframe into document + // insert the iframe into document elToAppend.insertBefore(iframe, elToAppend.firstChild); var iframeDoc = utils.getIframeDocument(iframe); @@ -54,11 +58,18 @@ var PubmaticAdapter = function PubmaticAdapter() { content += '' + 'window.pm_pub_id = "%%PM_PUB_ID%%";' + 'window.pm_optimize_adslots = [%%PM_OPTIMIZE_ADSLOTS%%];' + + 'window.kaddctr = "%%PM_ADDCTR%%";' + + 'window.kadgender = "%%PM_GENDER%%";' + + 'window.kadage = "%%PM_AGE%%";' + 'window.pm_async_callback_fn = "window.parent.$$PREBID_GLOBAL$$.handlePubmaticCallback";'; + content += ''; var map = {}; map.PM_PUB_ID = _pm_pub_id; + map.PM_ADDCTR = _pm_pub_kvs; + map.PM_GENDER = _pm_pub_gender; + map.PM_AGE = _pm_pub_age; map.PM_OPTIMIZE_ADSLOTS = _pm_optimize_adslots.map(function (adSlot) { return "'" + adSlot + "'"; }).join(','); @@ -78,8 +89,7 @@ var PubmaticAdapter = function PubmaticAdapter() { try { bidDetailsMap = iframe.contentWindow.bidDetailsMap; progKeyValueMap = iframe.contentWindow.progKeyValueMap; - } - catch(e) { + } catch (e) { utils.logError(e, 'Error parsing Pubmatic response'); } @@ -118,7 +128,7 @@ var PubmaticAdapter = function PubmaticAdapter() { adResponse.bidderCode = 'pubmatic'; adResponse.adSlot = bid.adSlot; adResponse.cpm = Number(adUnitInfo.bid); - adResponse.ad = unescape(adUnit.creative_tag); // jshint ignore:line + adResponse.ad = unescape(adUnit.creative_tag); adResponse.ad += utils.createTrackPixelIframeHtml(decodeURIComponent(adUnit.tracking_url)); adResponse.width = dimensions[0]; adResponse.height = dimensions[1]; @@ -137,7 +147,8 @@ var PubmaticAdapter = function PubmaticAdapter() { return { callBids: _callBids }; +} -}; +adaptermanager.registerBidAdapter(new PubmaticAdapter(), 'pubmatic'); module.exports = PubmaticAdapter; diff --git a/modules/pubwiseAnalyticsAdapter.js b/modules/pubwiseAnalyticsAdapter.js new file mode 100644 index 00000000000..0ed9c0620ea --- /dev/null +++ b/modules/pubwiseAnalyticsAdapter.js @@ -0,0 +1,53 @@ +import {ajax} from 'src/ajax'; +import adapter from 'src/AnalyticsAdapter'; +import adaptermanager from 'src/adaptermanager'; +const utils = require('src/utils'); + +/**** + * PubWise.io Analytics + * Contact: support@pubwise.io + * Developer: Stephen Johnston + */ + +const analyticsType = 'endpoint'; +let target_site = 'unknown'; +let target_url = 'https://staging.api.pubwise.io'; +let pw_version = '2.1.3'; + +let pubwiseAnalytics = Object.assign(adapter( + { + target_url, + analyticsType + } +), +{ + // Override AnalyticsAdapter functions by supplying custom methods + track({eventType, args}) { + /* + The args object is not always available, in addition neither is the config object + it is available on the first call and we can setup our config. Potential additional + PR for later, but this solves this for now. + */ + if (args !== undefined && args.config !== undefined && args.config.site !== undefined && args.config.endpoint !== undefined) { + target_site = args.config.site; + target_url = args.config.endpoint; + } + utils.logInfo('Sending PubWise Analytics Event ' + eventType, args); + ajax(target_url, + (result) => utils.logInfo('PubWise Analytics Result', result), JSON.stringify({ + eventType, + args, + target_site, + pw_version + }) + ); + } +}); + +adaptermanager.registerAnalyticsAdapter({ + adapter: pubwiseAnalytics, + code: 'pubwise' +}); + +export default pubwiseAnalytics; + diff --git a/modules/pulsepointAnalyticsAdapter.js b/modules/pulsepointAnalyticsAdapter.js new file mode 100644 index 00000000000..3a321fb0692 --- /dev/null +++ b/modules/pulsepointAnalyticsAdapter.js @@ -0,0 +1,19 @@ +/** + * pulsepoint.js - Analytics Adapter for PulsePoint + */ + +import adapter from 'src/AnalyticsAdapter'; +import adaptermanager from 'src/adaptermanager'; + +var pulsepointAdapter = adapter({ + global: 'PulsePointPrebidAnalytics', + handler: 'on', + analyticsType: 'bundle' +}); + +adaptermanager.registerAnalyticsAdapter({ + adapter: pulsepointAdapter, + code: 'pulsepoint' +}); + +export default pulsepointAdapter; diff --git a/src/adapters/pulsepoint.js b/modules/pulsepointBidAdapter.js similarity index 80% rename from src/adapters/pulsepoint.js rename to modules/pulsepointBidAdapter.js index e206c32550a..82c8df9a9c1 100644 --- a/src/adapters/pulsepoint.js +++ b/modules/pulsepointBidAdapter.js @@ -1,10 +1,10 @@ -var bidfactory = require('../bidfactory.js'); -var bidmanager = require('../bidmanager.js'); -var adloader = require('../adloader.js'); -var utils = require('../utils.js'); +var bidfactory = require('src/bidfactory.js'); +var bidmanager = require('src/bidmanager.js'); +var adloader = require('src/adloader.js'); +var utils = require('src/utils.js'); +var adaptermanager = require('src/adaptermanager'); var PulsePointAdapter = function PulsePointAdapter() { - var getJsStaticUrl = window.location.protocol + '//tag-st.contextweb.com/getjs.static.js'; var bidUrl = window.location.protocol + '//bid.contextweb.com/header/tag'; @@ -28,8 +28,8 @@ var PulsePointAdapter = function PulsePointAdapter() { try { var ppBidRequest = new window.pp.Ad(bidRequestOptions(bidRequest)); ppBidRequest.display(); - } catch(e) { - //register passback on any exceptions while attempting to fetch response. + } catch (e) { + // register passback on any exceptions while attempting to fetch response. utils.logError('pulsepoint.requestBid', 'ERROR', e); bidResponseAvailable(bidRequest); } @@ -44,8 +44,8 @@ var PulsePointAdapter = function PulsePointAdapter() { adUnitId: bidRequest.placementCode, callback: callback }; - for(var param in bidRequest.params) { - if(bidRequest.params.hasOwnProperty(param)) { + for (var param in bidRequest.params) { + if (bidRequest.params.hasOwnProperty(param)) { options[param] = bidRequest.params[param]; } } @@ -78,7 +78,8 @@ var PulsePointAdapter = function PulsePointAdapter() { return { callBids: _callBids }; - }; +adaptermanager.registerBidAdapter(new PulsePointAdapter(), 'pulsepoint'); + module.exports = PulsePointAdapter; diff --git a/modules/pulsepointLiteBidAdapter.js b/modules/pulsepointLiteBidAdapter.js new file mode 100644 index 00000000000..e7c67b86177 --- /dev/null +++ b/modules/pulsepointLiteBidAdapter.js @@ -0,0 +1,304 @@ +import {createBid} from 'src/bidfactory'; +import {addBidResponse} from 'src/bidmanager'; +import {logError, getTopWindowLocation} from 'src/utils'; +import {ajax} from 'src/ajax'; +import {STATUS} from 'src/constants'; +import adaptermanager from 'src/adaptermanager'; + +/** + * PulsePoint "Lite" Adapter. This adapter implementation is lighter than the + * alternative/original PulsePointAdapter because it has no external + * dependencies and relies on a single OpenRTB request to the PulsePoint + * bidder instead of separate requests per slot. + */ +function PulsePointLiteAdapter() { + const bidUrl = window.location.protocol + '//bid.contextweb.com/header/ortb'; + const ajaxOptions = { + method: 'POST', + withCredentials: true, + contentType: 'text/plain' + }; + const NATIVE_DEFAULTS = { + TITLE_LEN: 100, + DESCR_LEN: 200, + SPONSORED_BY_LEN: 50, + IMG_MIN: 150, + ICON_MIN: 50, + }; + + /** + * Makes the call to PulsePoint endpoint and registers bids. + */ + function _callBids(bidRequest) { + try { + // construct the openrtb bid request from slots + const request = { + imp: bidRequest.bids.map(slot => impression(slot)), + site: site(bidRequest), + device: device(), + }; + ajax(bidUrl, (rawResponse) => { + bidResponseAvailable(bidRequest, rawResponse); + }, JSON.stringify(request), ajaxOptions); + } catch (e) { + // register passback on any exceptions while attempting to fetch response. + logError('pulsepoint.requestBid', 'ERROR', e); + bidResponseAvailable(bidRequest); + } + } + + /** + * Callback for bids, after the call to PulsePoint completes. + */ + function bidResponseAvailable(bidRequest, rawResponse) { + const idToSlotMap = {}; + const idToBidMap = {}; + // extract the request bids and the response bids, keyed by impr-id + bidRequest.bids.forEach((slot) => { + idToSlotMap[slot.bidId] = slot; + }); + const bidResponse = parse(rawResponse); + if (bidResponse) { + bidResponse.seatbid.forEach(seatBid => seatBid.bid.forEach((bid) => { + idToBidMap[bid.impid] = bid; + })); + } + // register the responses + Object.keys(idToSlotMap).forEach((id) => { + if (idToBidMap[id]) { + const size = adSize(idToSlotMap[id]); + const bid = createBid(STATUS.GOOD, bidRequest); + bid.bidderCode = bidRequest.bidderCode; + bid.cpm = idToBidMap[id].price; + bid.adId = id; + if (isNative(idToSlotMap[id])) { + bid.native = nativeResponse(idToSlotMap[id], idToBidMap[id]); + bid.mediaType = 'native'; + } else { + bid.ad = idToBidMap[id].adm; + bid.width = size[0]; + bid.height = size[1]; + } + addBidResponse(idToSlotMap[id].placementCode, bid); + } else { + const passback = createBid(STATUS.NO_BID, bidRequest); + passback.bidderCode = bidRequest.bidderCode; + passback.adId = id; + addBidResponse(idToSlotMap[id].placementCode, passback); + } + }); + } + + /** + * Produces an OpenRTBImpression from a slot config. + */ + function impression(slot) { + return { + id: slot.bidId, + banner: banner(slot), + native: native(slot), + tagid: slot.params.ct.toString(), + }; + } + + /** + * Produces an OpenRTB Banner object for the slot given. + */ + function banner(slot) { + const size = adSize(slot); + return slot.nativeParams ? null : { + w: size[0], + h: size[1], + }; + } + + /** + * Produces an OpenRTB Native object for the slot given. + */ + function native(slot) { + if (slot.nativeParams) { + const assets = []; + addAsset(assets, titleAsset(assets.length + 1, slot.nativeParams.title, NATIVE_DEFAULTS.TITLE_LEN)); + addAsset(assets, dataAsset(assets.length + 1, slot.nativeParams.body, 2, NATIVE_DEFAULTS.DESCR_LEN)); + addAsset(assets, dataAsset(assets.length + 1, slot.nativeParams.sponsoredBy, 1, NATIVE_DEFAULTS.SPONSORED_BY_LEN)); + addAsset(assets, imageAsset(assets.length + 1, slot.nativeParams.icon, 1, NATIVE_DEFAULTS.ICON_MIN, NATIVE_DEFAULTS.ICON_MIN)); + addAsset(assets, imageAsset(assets.length + 1, slot.nativeParams.image, 3, NATIVE_DEFAULTS.IMG_MIN, NATIVE_DEFAULTS.IMG_MIN)); + return { + request: JSON.stringify({ assets }), + ver: '1.1', + }; + } + return null; + } + + /** + * Helper method to add an asset to the assets list. + */ + function addAsset(assets, asset) { + if (asset) { + assets.push(asset); + } + } + + /** + * Produces a Native Title asset for the configuration given. + */ + function titleAsset(id, params, defaultLen) { + if (params) { + return { + id: id, + required: params.required ? 1 : 0, + title: { + len: params.len || defaultLen, + }, + }; + } + return null; + } + + /** + * Produces a Native Image asset for the configuration given. + */ + function imageAsset(id, params, type, defaultMinWidth, defaultMinHeight) { + return params ? { + id: id, + required: params.required ? 1 : 0, + img: { + type, + wmin: params.wmin || defaultMinWidth, + hmin: params.hmin || defaultMinHeight, + } + } : null; + } + + /** + * Produces a Native Data asset for the configuration given. + */ + function dataAsset(id, params, type, defaultLen) { + return params ? { + id: id, + required: params.required ? 1 : 0, + data: { + type, + len: params.len || defaultLen, + } + } : null; + } + + /** + * Produces an OpenRTB site object. + */ + function site(bidderRequest) { + const pubId = bidderRequest.bids.length > 0 ? bidderRequest.bids[0].params.cp : '0'; + return { + publisher: { + id: pubId.toString(), + }, + ref: referrer(), + page: getTopWindowLocation().href, + }; + } + + /** + * Attempts to capture the referrer url. + */ + function referrer() { + try { + return window.top.document.referrer; + } catch (e) { + return document.referrer; + } + } + + /** + * Produces an OpenRTB Device object. + */ + function device() { + return { + ua: navigator.userAgent, + language: (navigator.language || navigator.browserLanguage || navigator.userLanguage || navigator.systemLanguage), + }; + } + + /** + * Safely parses the input given. Returns null on + * parsing failure. + */ + function parse(rawResponse) { + try { + if (rawResponse) { + return JSON.parse(rawResponse); + } + } catch (ex) { + logError('pulsepointLite.safeParse', 'ERROR', ex); + } + return null; + } + + /** + * Determines the AdSize for the slot. + */ + function adSize(slot) { + if (slot.params.cf) { + const size = slot.params.cf.toUpperCase().split('X'); + const width = parseInt(slot.params.cw || size[0], 10); + const height = parseInt(slot.params.ch || size[1], 10); + return [width, height]; + } + return [1, 1]; + } + + /** + * Parses the native response from the Bid given. + */ + function nativeResponse(slot, bid) { + if (slot.nativeParams) { + const nativeAd = parse(bid.adm); + const keys = {}; + if (nativeAd && nativeAd.native && nativeAd.native.assets) { + nativeAd.native.assets.forEach((asset) => { + keys.title = asset.title ? asset.title.text : keys.title; + keys.body = asset.data && asset.data.type === 2 ? asset.data.value : keys.body; + keys.sponsoredBy = asset.data && asset.data.type === 1 ? asset.data.value : keys.sponsoredBy; + keys.image = asset.img && asset.img.type === 3 ? asset.img.url : keys.image; + keys.icon = asset.img && asset.img.type === 1 ? asset.img.url : keys.icon; + }); + if (nativeAd.native.link) { + keys.clickUrl = encodeURIComponent(nativeAd.native.link.url); + } + keys.impressionTrackers = nativeAd.native.imptrackers; + return keys; + } + } + return null; + } + + /** + * Parses the native response from the Bid given. + */ + function isNative(slot) { + return !!slot.nativeParams; + } + + return { + callBids: _callBids + }; +} + +PulsePointLiteAdapter.createNew = function() { + return new PulsePointLiteAdapter(); +} +/** + * "pulseLite" will be the adapter name going forward. "pulsepointLite" to be + * deprecated, but kept here for backwards compatibility. + * Reason is key truncation. When the Publisher opts for sending all bids to DFP, then + * the keys get truncated due to the limit in key-size (20 characters, detailed + * here https://support.google.com/dfp_premium/answer/1628457?hl=en). Here is an + * example, where keys got truncated when using the "pulsepointLite" alias - "hb_adid_pulsepointLi=1300bd87d59c4c2" +*/ +adaptermanager.registerBidAdapter(new PulsePointLiteAdapter(), 'pulseLite', { + supportedMediaTypes: [ 'native' ] +}); +adaptermanager.aliasBidAdapter('pulseLite', 'pulsepointLite'); + +module.exports = PulsePointLiteAdapter; diff --git a/src/adapters/quantcast.js b/modules/quantcastBidAdapter.js similarity index 64% rename from src/adapters/quantcast.js rename to modules/quantcastBidAdapter.js index cbf6f1c9028..b0e38cea2b1 100644 --- a/src/adapters/quantcast.js +++ b/modules/quantcastBidAdapter.js @@ -1,52 +1,51 @@ -const utils = require('../utils.js'); -const bidfactory = require('../bidfactory.js'); -const bidmanager = require('../bidmanager.js'); -const ajax = require('../ajax.js'); -const CONSTANTS = require('../constants.json'); +const utils = require('src/utils.js'); +const bidfactory = require('src/bidfactory.js'); +const bidmanager = require('src/bidmanager.js'); +const ajax = require('src/ajax.js'); +const CONSTANTS = require('src/constants.json'); +const adaptermanager = require('src/adaptermanager'); const QUANTCAST_CALLBACK_URL = 'http://global.qc.rtb.quantserve.com:8080/qchb'; var QuantcastAdapter = function QuantcastAdapter() { - const BIDDER_CODE = 'quantcast'; const DEFAULT_BID_FLOOR = 0.0000000001; let bidRequests = {}; let returnEmptyBid = function(bidId) { - var bidRequested = utils.getBidRequest(bidId); - if (!utils.isEmpty(bidRequested)) { - let bid = bidfactory.createBid(CONSTANTS.STATUS.NO_BID, bidRequested); - bid.bidderCode = BIDDER_CODE; - bidmanager.addBidResponse(bidRequested.placementCode, bid); - } - return; - }; + var bidRequested = utils.getBidRequest(bidId); + if (!utils.isEmpty(bidRequested)) { + let bid = bidfactory.createBid(CONSTANTS.STATUS.NO_BID, bidRequested); + bid.bidderCode = BIDDER_CODE; + bidmanager.addBidResponse(bidRequested.placementCode, bid); + } + }; - //expose the callback to the global object: + // expose the callback to the global object: $$PREBID_GLOBAL$$.handleQuantcastCB = function (responseText) { - if(utils.isEmpty(responseText)) { + if (utils.isEmpty(responseText)) { return; } let response = null; try { response = JSON.parse(responseText); - } catch(e) { + } catch (e) { // Malformed JSON utils.logError("Malformed JSON received from server - can't do anything here"); return; } - if(response === null || !response.hasOwnProperty('bids') || utils.isEmpty(response.bids)) { + if (response === null || !response.hasOwnProperty('bids') || utils.isEmpty(response.bids)) { utils.logError("Sub-optimal JSON received from server - can't do anything here"); return; } - for(let i = 0; i < response.bids.length; i++) { + for (let i = 0; i < response.bids.length; i++) { let seatbid = response.bids[i]; let key = seatbid.placementCode; var request = bidRequests[key]; - if(request === null || request === undefined) { + if (request === null || request === undefined) { return returnEmptyBid(seatbid.placementCode); } // This line is required since this is the field @@ -64,7 +63,6 @@ var QuantcastAdapter = function QuantcastAdapter() { bidmanager.addBidResponse(request.bidId, responseBid); } - }; function callBids(params) { @@ -84,34 +82,34 @@ var QuantcastAdapter = function QuantcastAdapter() { var bidSizes = []; utils._each(bid.sizes, function (size) { bidSizes.push({ - 'width' : size[0], - 'height' : size[1] + 'width': size[0], + 'height': size[1] }); }); bidRequests[key] = bidRequests[key] || { - 'publisherId' : publisherId, - 'requestId' : bid.bidId, - 'bidId' : bid.bidId, - 'site' : { - 'page' : loc.href, - 'referrer' : referrer, - 'domain' : domain, + 'publisherId': publisherId, + 'requestId': bid.bidId, + 'bidId': bid.bidId, + 'site': { + 'page': loc.href, + 'referrer': referrer, + 'domain': domain, }, - 'imp' : [{ + 'imp': [{ - 'banner' : { - 'battr' : bid.params.battr, - 'sizes' : bidSizes, + 'banner': { + 'battr': bid.params.battr, + 'sizes': bidSizes, }, - 'placementCode' : bid.placementCode, - 'bidFloor' : bid.params.bidFloor || DEFAULT_BID_FLOOR, + 'placementCode': bid.placementCode, + 'bidFloor': bid.params.bidFloor || DEFAULT_BID_FLOOR, }] }; utils._each(bidRequests, function (bidRequest) { ajax.ajax(QUANTCAST_CALLBACK_URL, $$PREBID_GLOBAL$$.handleQuantcastCB, JSON.stringify(bidRequest), { - method : 'POST', + method: 'POST', withCredentials: true }); }); @@ -131,5 +129,6 @@ exports.createNew = function() { return new QuantcastAdapter(); }; +adaptermanager.registerBidAdapter(new QuantcastAdapter(), 'quantcast'); module.exports = QuantcastAdapter; diff --git a/modules/rhythmoneBidAdapter.js b/modules/rhythmoneBidAdapter.js new file mode 100644 index 00000000000..5ba6bff78b9 --- /dev/null +++ b/modules/rhythmoneBidAdapter.js @@ -0,0 +1,301 @@ +/* eslint indent: 0 */ +import {ajax} from 'src/ajax'; +import adaptermanager from 'src/adaptermanager'; + +var bidmanager = require('src/bidmanager.js'), + bidfactory = require('src/bidfactory.js'), + CONSTANTS = require('src/constants.json'); + +function RhythmoneAdapter (bidManager, global, loader) { + var version = '0.9.0.0', + defaultZone = '1r', + defaultPath = 'mvo', + debug = false, + requestCompleted = false, + placementCodes = {}, + loadStart, + configuredPlacements = [], + fat = /(^v|(\.0)+$)/gi; + + if (typeof global === 'undefined') + { global = window; } + + if (typeof bidManager === 'undefined') + { bidManager = bidmanager; } + + if (typeof loader === 'undefined') + { loader = ajax; } + + function applyMacros(txt, values) { + return txt.replace(/\{([^\}]+)\}/g, function(match) { + var v = values[match.replace(/[\{\}]/g, '').toLowerCase()]; + if (typeof v !== 'undefined') return v; + return match; + }); + } + + function load(bidParams, url, callback) { + loader(url, function(responseText, response) { + if (response.status === 200) + { callback(200, 'success', response.responseText); } + else + { callback(-1, 'http error ' + response.status, response.responseText); } + }, false, {method: 'GET', withCredentials: true}); + } + + function flashInstalled() { + var n = global.navigator, + p = n.plugins, + m = n.mimeTypes, + t = 'application/x-shockwave-flash', + x = global.ActiveXObject; + + if (p && + p['Shockwave Flash'] && + m && + m[t] && + m[t].enabledPlugin) + { return true; } + + if (x) { + try { if ((new global.ActiveXObject('ShockwaveFlash.ShockwaveFlash'))) return true; } + catch (e) {} + } + + return false; + } + + var bidderCode = 'rhythmone'; + + function attempt(valueFunction, defaultValue) { + try { + return valueFunction(); + } catch (ex) {} + return defaultValue; + } + + function logToConsole(txt) { + if (debug) + { console.log(txt); } + } + + function getBidParameters(bids) { + for (var i = 0; i < bids.length; i++) + { if (typeof bids[i].params === 'object' && bids[i].params.placementId) + { return bids[i].params; } } + return null; + } + + function noBids(params) { + for (var i = 0; i < params.bids.length; i++) { + if (params.bids[i].success !== 1) { + logToConsole('registering nobid for slot ' + params.bids[i].placementCode); + var bid = bidfactory.createBid(CONSTANTS.STATUS.NO_BID); + bid.bidderCode = bidderCode; + bidmanager.addBidResponse(params.bids[i].placementCode, bid); + } + } + } + + function getRMPURL(bidParams, bids) { + var endpoint = '//tag.1rx.io/rmp/{placementId}/0/{path}?z={zone}', + query = []; + + if (typeof bidParams.endpoint === 'string') + { endpoint = bidParams.endpoint; } + + if (typeof bidParams.zone === 'string') + { defaultZone = bidParams.zone; } + + if (typeof bidParams.path === 'string') + { defaultPath = bidParams.path; } + + if (bidParams.debug === true) + { debug = true; } + + if (bidParams.trace === true) + { query.push('trace=true'); } + + endpoint = applyMacros(endpoint, { + placementid: bidParams.placementId, + zone: defaultZone, + path: defaultPath + }); + + function p(k, v) { + if (v instanceof Array) + { v = v.join(','); } + if (typeof v !== 'undefined') + { query.push(encodeURIComponent(k) + '=' + encodeURIComponent(v)); } + } + + p('domain', attempt(function() { + var d = global.document.location.ancestorOrigins; + if (d && d.length > 0) + { return d[d.length - 1]; } + return global.top.document.location.hostname; // try/catch is in the attempt function + }, '')); + p('title', attempt(function() { return global.top.document.title; }, '')); // try/catch is in the attempt function + p('url', attempt(function() { + var l; + try { l = global.top.document.location.href.toString(); } // try/catch is in the attempt function + catch (ex) { l = global.document.location.href.toString(); } + return l; + }, '')); + p('dsh', (global.screen ? global.screen.height : '')); + p('dsw', (global.screen ? global.screen.width : '')); + p('tz', (new Date()).getTimezoneOffset()); + p('dtype', ((/(ios|ipod|ipad|iphone|android)/i).test(global.navigator.userAgent) ? 1 : ((/(smart[-]?tv|hbbtv|appletv|googletv|hdmi|netcast\.tv|viera|nettv|roku|\bdtv\b|sonydtv|inettvbrowser|\btv\b)/i).test(global.navigator.userAgent) ? 3 : 2))); + p('flash', (flashInstalled() ? 1 : 0)); + + var heights = [], + widths = [], + floors = [], + mediaTypes = [], + i = 0; + + configuredPlacements = []; + + p('hbv', global.$$PREBID_GLOBAL$$.version.replace(fat, '') + ',' + version.replace(fat, '')); + + for (; i < bids.length; i++) { + var th = [], tw = []; + + if (bids[i].sizes.length > 0 && typeof bids[i].sizes[0] === 'number') + { bids[i].sizes = [bids[i].sizes]; } + + for (var j = 0; j < bids[i].sizes.length; j++) { + tw.push(bids[i].sizes[j][0]); + th.push(bids[i].sizes[j][1]); + } + configuredPlacements.push(bids[i].placementCode); + heights.push(th.join('|')); + widths.push(tw.join('|')); + mediaTypes.push(((/video/i).test(bids[i].mediaType) ? 'v' : 'd')); + floors.push(0); + } + + p('imp', configuredPlacements); + p('w', widths); + p('h', heights); + p('floor', floors); + p('t', mediaTypes); + + endpoint += '&' + query.join('&'); + + return endpoint; + } + + function sendAuditBeacon(placementId) { + var data = { + doc_version: 1, + doc_type: 'Prebid Audit', + placement_id: placementId + }, + ao = document.location.ancestorOrigins, + q = [], + u = '//hbevents.1rx.io/audit?', + i = new Image(); + + if (ao && ao.length > 0) { + data.ancestor_origins = ao[ao.length - 1]; + } + + data.popped = window.opener !== null ? 1 : 0; + data.framed = window.top === window ? 0 : 1; + + try { + data.url = window.top.document.location.href.toString(); + } catch (ex) { + data.url = window.document.location.href.toString(); + } + + var prebid_instance = global.$$PREBID_GLOBAL$$; + + data.prebid_version = prebid_instance.version.replace(fat, ''); + data.response_ms = (new Date()).getTime() - loadStart; + data.placement_codes = configuredPlacements.join(','); + data.bidder_version = version; + data.prebid_timeout = prebid_instance.cbTimeout || prebid_instance.bidderTimeout; + + for (var k in data) { + q.push(encodeURIComponent(k) + '=' + encodeURIComponent((typeof data[k] === 'object' ? JSON.stringify(data[k]) : data[k]))); + } + + q.sort(); + i.src = u + q.join('&'); + } + + this.callBids = function(params) { + var slotMap = {}, + bidParams = getBidParameters(params.bids); + + debug = (bidParams !== null && bidParams.debug === true); + + if (bidParams === null) { + noBids(params); + return; + } + + for (var i = 0; i < params.bids.length; i++) + { slotMap[params.bids[i].placementCode] = params.bids[i]; } + + loadStart = (new Date()).getTime(); + load(bidParams, getRMPURL(bidParams, params.bids), function(code, msg, txt) { + // send quality control beacon here + sendAuditBeacon(bidParams.placementId); + + requestCompleted = true; + + logToConsole('response text: ' + txt); + + if (code !== -1) { + try { + var result = JSON.parse(txt), + registerBid = function(bid) { + slotMap[bid.impid].success = 1; + + var pbResponse = bidfactory.createBid(CONSTANTS.STATUS.GOOD), + placementCode = slotMap[bid.impid].placementCode; + + placementCodes[placementCode] = false; + + pbResponse.bidderCode = bidderCode; + pbResponse.cpm = parseFloat(bid.price); + pbResponse.width = bid.w; + pbResponse.height = bid.h; + + if ((/video/i).test(slotMap[bid.impid].mediaType)) { + pbResponse.mediaType = 'video'; + pbResponse.vastUrl = bid.nurl; + pbResponse.descriptionUrl = bid.nurl; + } + else + { pbResponse.ad = bid.adm; } + + logToConsole('registering bid ' + placementCode + ' ' + JSON.stringify(pbResponse)); + + bidManager.addBidResponse(placementCode, pbResponse); + }; + + for (i = 0; result.seatbid && i < result.seatbid.length; i++) + { for (var j = 0; result.seatbid[i].bid && j < result.seatbid[i].bid.length; j++) { + registerBid(result.seatbid[i].bid[j]); + } } + } + catch (ex) {} + } + + // if no bids are successful, inform prebid + noBids(params); + }); + + logToConsole('version: ' + version); + }; +} + +adaptermanager.registerBidAdapter(new RhythmoneAdapter(), 'rhythmone', { + supportedMediaTypes: ['video'] +}); + +module.exports = RhythmoneAdapter; diff --git a/src/adapters/analytics/roxot.js b/modules/roxotAnalyticsAdapter.js similarity index 73% rename from src/adapters/analytics/roxot.js rename to modules/roxotAnalyticsAdapter.js index 7668d0ba050..99ea6bc9977 100644 --- a/src/adapters/analytics/roxot.js +++ b/modules/roxotAnalyticsAdapter.js @@ -1,8 +1,9 @@ -import {ajax} from "src/ajax"; -import adapter from "AnalyticsAdapter"; -import CONSTANTS from "src/constants.json"; +import {ajax} from 'src/ajax'; +import adapter from 'src/AnalyticsAdapter'; +import CONSTANTS from 'src/constants.json'; +import adaptermanager from 'src/adaptermanager'; -const utils = require('../../utils'); +const utils = require('src/utils'); const url = '//pa.rxthdr.com/analytic'; const analyticsType = 'endpoint'; @@ -36,12 +37,16 @@ function buildEventStack() { function send(eventType, data, sendDataType) { let fullUrl = url + '?publisherIds[]=' + initOptions.publisherIds.join('&publisherIds[]=') + '&host=' + window.location.hostname; - - ajax( - fullUrl, - (result) => utils.logInfo('Event ' + eventType + ' sent ' + sendDataType + ' to roxot prebid analytic with result' + result), - JSON.stringify(data) - ); + let xhr = new XMLHttpRequest(); + xhr.open('POST', fullUrl, true); + xhr.setRequestHeader('Content-Type', 'text/plain'); + xhr.withCredentials = true; + xhr.onreadystatechange = function(result) { + if (this.readyState != 4) return; + + utils.logInfo('Event ' + eventType + ' sent ' + sendDataType + ' to roxot prebid analytic with result' + result); + } + xhr.send(JSON.stringify(data)); } function pushEvent(eventType, args) { @@ -62,7 +67,7 @@ let roxotAdapter = Object.assign(adapter({url, analyticsType}), let info = Object.assign({}, args); if (info && info.ad) { - info.ad = ""; + info.ad = ''; } if (eventType === auctionInitConst) { @@ -71,7 +76,7 @@ let roxotAdapter = Object.assign(adapter({url, analyticsType}), } if ((eventType === bidWonConst) && auctionStatus === 'not_started') { - buildBidWon(eventType,info); + buildBidWon(eventType, info); send(eventType, bidWon, 'bidWon'); return; } @@ -95,4 +100,9 @@ roxotAdapter.enableAnalytics = function (config) { roxotAdapter.originEnableAnalytics(config); }; +adaptermanager.registerAnalyticsAdapter({ + adapter: roxotAdapter, + code: 'roxot' +}); + export default roxotAdapter; diff --git a/src/adapters/roxot.js b/modules/roxotBidAdapter.js similarity index 83% rename from src/adapters/roxot.js rename to modules/roxotBidAdapter.js index 171fe49e5ec..a2b9b6ca6dc 100644 --- a/src/adapters/roxot.js +++ b/modules/roxotBidAdapter.js @@ -1,11 +1,12 @@ -var CONSTANTS = require('../constants.json'); -var utils = require('../utils.js'); -var bidfactory = require('../bidfactory.js'); -var bidmanager = require('../bidmanager.js'); -var adloader = require('../adloader'); +var CONSTANTS = require('src/constants.json'); +var utils = require('src/utils.js'); +var bidfactory = require('src/bidfactory.js'); +var bidmanager = require('src/bidmanager.js'); +var adloader = require('src/adloader'); +var adaptermanager = require('src/adaptermanager'); var RoxotAdapter = function RoxotAdapter() { - var roxotUrl = "r.rxthdr.com"; + var roxotUrl = 'r.rxthdr.com'; $$PREBID_GLOBAL$$.roxotResponseHandler = roxotResponseHandler; @@ -57,8 +58,8 @@ var RoxotAdapter = function RoxotAdapter() { var placementCode = ''; var bidReq = $$PREBID_GLOBAL$$ - ._bidsRequested.find(bidSet => bidSet.bidderCode === 'roxot') - .bids.find(bid => bid.bidId === roxotBid.bidId); + ._bidsRequested.find(bidSet => bidSet.bidderCode === 'roxot') + .bids.find(bid => bid.bidId === roxotBid.bidId); if (!bidReq) { return pushErrorBid(placementCode); @@ -110,4 +111,6 @@ var RoxotAdapter = function RoxotAdapter() { } }; -module.exports = RoxotAdapter; \ No newline at end of file +adaptermanager.registerBidAdapter(new RoxotAdapter(), 'roxot'); + +module.exports = RoxotAdapter; diff --git a/src/adapters/rubicon.js b/modules/rubiconBidAdapter.js similarity index 72% rename from src/adapters/rubicon.js rename to modules/rubiconBidAdapter.js index cf386a34370..a09c1c413af 100644 --- a/src/adapters/rubicon.js +++ b/modules/rubiconBidAdapter.js @@ -1,6 +1,7 @@ -import * as Adapter from './adapter.js'; +import * as Adapter from 'src/adapter'; import bidfactory from 'src/bidfactory'; import bidmanager from 'src/bidmanager'; +import adaptermanager from 'src/adaptermanager'; import * as utils from 'src/utils'; import { ajax } from 'src/ajax'; import { STATUS } from 'src/constants'; @@ -12,6 +13,10 @@ function getIntegration() { return 'pbjs_lite_' + $$PREBID_GLOBAL$$.version; } +function isSecure() { + return location.protocol === 'https:'; +} + // use protocol relative urls for http or https const FASTLANE_ENDPOINT = '//fastlane.rubiconproject.com/a/api/fastlane.json'; const VIDEO_ENDPOINT = '//fastlane-adv.rubiconproject.com/v1/auction/video'; @@ -19,42 +24,53 @@ const VIDEO_ENDPOINT = '//fastlane-adv.rubiconproject.com/v1/auction/video'; const TIMEOUT_BUFFER = 500; var sizeMap = { - 1:'468x60', - 2:'728x90', - 8:'120x600', - 9:'160x600', - 10:'300x600', - 15:'300x250', - 16:'336x280', - 19:'300x100', - 43:'320x50', - 44:'300x50', - 48:'300x300', - 54:'300x1050', - 55:'970x90', - 57:'970x250', - 58:'1000x90', - 59:'320x80', - 61:'1000x1000', - 65:'640x480', - 67:'320x480', - 68:'1800x1000', - 72:'320x320', - 73:'320x160', - 83:'480x300', - 94:'970x310', - 96:'970x210', - 101:'480x320', - 102:'768x1024', - 113:'1000x300', - 117:'320x100', - 125:'800x250', - 126:'200x600' + 1: '468x60', + 2: '728x90', + 8: '120x600', + 9: '160x600', + 10: '300x600', + 14: '250x250', + 15: '300x250', + 16: '336x280', + 19: '300x100', + 31: '980x120', + 32: '250x360', + 33: '180x500', + 35: '980x150', + 37: '468x400', + 38: '930x180', + 43: '320x50', + 44: '300x50', + 48: '300x300', + 54: '300x1050', + 55: '970x90', + 57: '970x250', + 58: '1000x90', + 59: '320x80', + 60: '320x150', + 61: '1000x1000', + 65: '640x480', + 67: '320x480', + 68: '1800x1000', + 72: '320x320', + 73: '320x160', + 78: '980x240', + 79: '980x300', + 80: '980x400', + 83: '480x300', + 94: '970x310', + 96: '970x210', + 101: '480x320', + 102: '768x1024', + 103: '480x280', + 113: '1000x300', + 117: '320x100', + 125: '800x250', + 126: '200x600' }; utils._each(sizeMap, (item, key) => sizeMap[item] = key); function RubiconAdapter() { - function _callBids(bidderRequest) { var bids = bidderRequest.bids || []; @@ -86,7 +102,7 @@ function RubiconAdapter() { } ); } - } catch(err) { + } catch (err) { utils.logError('Error sending rubicon request for placement code ' + bid.placementCode, null, err); addErrorBid(); } @@ -122,23 +138,40 @@ function RubiconAdapter() { return [window.screen.width, window.screen.height].join('x'); } + function _getDigiTrustQueryParams() { + function getDigiTrustId() { + let digiTrustUser = window.DigiTrust && window.DigiTrust.getUser({member: 'T9QSFKPDN9'}); + return digiTrustUser && digiTrustUser.success && digiTrustUser.identity || null; + } + let digiTrustId = getDigiTrustId(); + // Verify there is an ID and this user has not opted out + if (!digiTrustId || digiTrustId.privacy && digiTrustId.privacy.optout) { + return []; + } + return [ + 'dt.id', digiTrustId.id, + 'dt.keyv', digiTrustId.keyv, + 'dt.pref', 0 + ]; + } + function buildVideoRequestPayload(bid, bidderRequest) { bid.startTime = new Date().getTime(); let params = bid.params; - if(!params || typeof params.video !== 'object') { + if (!params || typeof params.video !== 'object') { throw 'Invalid Video Bid'; } let size; - if(params.video.playerWidth && params.video.playerHeight) { + if (params.video.playerWidth && params.video.playerHeight) { size = [ params.video.playerWidth, params.video.playerHeight ]; - } else if( - Array.isArray(bid.sizes) && bid.sizes.length > 0 && + } else if ( + Array.isArray(bid.sizes) && bid.sizes.length > 0 && Array.isArray(bid.sizes[0]) && bid.sizes[0].length > 1 ) { size = bid.sizes[0]; @@ -146,9 +179,9 @@ function RubiconAdapter() { throw 'Invalid Video Bid - No size provided'; } - let postData = { + let postData = { page_url: !params.referrer ? utils.getTopWindowUrl() : params.referrer, - resolution: _getScreenResolution(), + resolution: _getScreenResolution(), account_id: params.accountId, integration: getIntegration(), timeout: bidderRequest.timeout - (Date.now() - bidderRequest.auctionStart + TIMEOUT_BUFFER), @@ -171,27 +204,27 @@ function RubiconAdapter() { }; // check and add inventory, keywords, visitor and size_id data - if(params.video.size_id) { + if (params.video.size_id) { slotData.size_id = params.video.size_id; } else { throw 'Invalid Video Bid - Invalid Ad Type!'; } - if(params.inventory && typeof params.inventory === 'object') { + if (params.inventory && typeof params.inventory === 'object') { slotData.inventory = params.inventory; } - if(params.keywords && Array.isArray(params.keywords)) { + if (params.keywords && Array.isArray(params.keywords)) { slotData.keywords = params.keywords; } - if(params.visitor && typeof params.visitor === 'object') { + if (params.visitor && typeof params.visitor === 'object') { slotData.visitor = params.visitor; } postData.slots.push(slotData); - return(JSON.stringify(postData)); + return (JSON.stringify(postData)); } function buildOptimizedCall(bid) { @@ -215,15 +248,15 @@ function RubiconAdapter() { position = position || 'btf'; // use rubicon sizes if provided, otherwise adUnit.sizes - var parsedSizes = RubiconAdapter.masSizeOrdering(Array.isArray(bid.params.sizes) ? - bid.params.sizes.map(size => (sizeMap[size] || '').split('x')) : bid.sizes + var parsedSizes = RubiconAdapter.masSizeOrdering(Array.isArray(bid.params.sizes) + ? bid.params.sizes.map(size => (sizeMap[size] || '').split('x')) : bid.sizes ); - if(parsedSizes.length < 1) { + if (parsedSizes.length < 1) { throw 'no valid sizes'; } - if(!/^\d+$/.test(accountId)) { + if (!/^\d+$/.test(accountId)) { throw 'invalid accountId provided'; } @@ -236,17 +269,18 @@ function RubiconAdapter() { 'alt_size_ids', parsedSizes.slice(1).join(',') || undefined, 'p_pos', position, 'rp_floor', floor, + 'rp_secure', isSecure() ? '1' : '0', 'tk_flint', getIntegration(), 'p_screen_res', _getScreenResolution(), 'kw', keywords, 'tk_user_key', userId ]; - if(visitor !== null && typeof visitor === 'object') { + if (visitor !== null && typeof visitor === 'object') { utils._each(visitor, (item, key) => queryString.push(`tg_v.${key}`, item)); } - if(inventory !== null && typeof inventory === 'object') { + if (inventory !== null && typeof inventory === 'object') { utils._each(inventory, (item, key) => queryString.push(`tg_i.${key}`, item)); } @@ -255,10 +289,12 @@ function RubiconAdapter() { 'rf', !pageUrl ? utils.getTopWindowUrl() : pageUrl ); + queryString = queryString.concat(_getDigiTrustQueryParams()); + return queryString.reduce( (memo, curr, index) => - index % 2 === 0 && queryString[index + 1] !== undefined ? - memo + curr + '=' + encodeURIComponent(queryString[index + 1]) + '&' : memo, + index % 2 === 0 && queryString[index + 1] !== undefined + ? memo + curr + '=' + encodeURIComponent(queryString[index + 1]) + '&' : memo, FASTLANE_ENDPOINT + '?' ).slice(0, -1); // remove trailing & } @@ -275,11 +311,11 @@ function RubiconAdapter() { function handleRpCB(responseText, bidRequest) { var responseObj = JSON.parse(responseText), // can throw - ads = responseObj.ads, - adResponseKey = bidRequest.placementCode; + ads = responseObj.ads, + adResponseKey = bidRequest.placementCode; // check overall response - if(typeof responseObj !== 'object' || responseObj.status !== 'ok') { + if (typeof responseObj !== 'object' || responseObj.status !== 'ok') { throw 'bad response'; } @@ -289,7 +325,7 @@ function RubiconAdapter() { } // check the ad response - if(!Array.isArray(ads) || ads.length < 1) { + if (!Array.isArray(ads) || ads.length < 1) { throw 'invalid ad response'; } @@ -297,12 +333,12 @@ function RubiconAdapter() { ads = ads.sort(_adCpmSort); ads.forEach(ad => { - if(ad.status !== 'ok') { + if (ad.status !== 'ok') { throw 'bad ad status'; } - //store bid response - //bid status is good (indicating 1) + // store bid response + // bid status is good (indicating 1) var bid = bidfactory.createBid(STATUS.GOOD, bidRequest); bid.creative_id = ad.ad_id; bid.bidderCode = bidRequest.bidder; @@ -351,7 +387,7 @@ RubiconAdapter.masSizeOrdering = function(sizes) { // map sizes while excluding non-matches .reduce((result, size) => { let mappedSize = parseInt(sizeMap[size], 10); - if(mappedSize) { + if (mappedSize) { result.push(mappedSize); } return result; @@ -359,13 +395,13 @@ RubiconAdapter.masSizeOrdering = function(sizes) { .sort((first, second) => { // sort by MAS_SIZE_PRIORITY priority order let firstPriority = MAS_SIZE_PRIORITY.indexOf(first), - secondPriority = MAS_SIZE_PRIORITY.indexOf(second); + secondPriority = MAS_SIZE_PRIORITY.indexOf(second); - if(firstPriority > -1 || secondPriority > -1) { - if(firstPriority === -1) { + if (firstPriority > -1 || secondPriority > -1) { + if (firstPriority === -1) { return 1; } - if(secondPriority === -1) { + if (secondPriority === -1) { return -1; } return firstPriority - secondPriority; @@ -380,5 +416,10 @@ RubiconAdapter.createNew = function() { return new RubiconAdapter(); }; +adaptermanager.registerBidAdapter(new RubiconAdapter(), RUBICON_BIDDER_CODE, { + supportedMediaTypes: ['video'] +}); +adaptermanager.aliasBidAdapter(RUBICON_BIDDER_CODE, 'rubiconLite'); + module.exports = RubiconAdapter; diff --git a/src/adapters/sekindoUM.js b/modules/sekindoUMBidAdapter.js similarity index 73% rename from src/adapters/sekindoUM.js rename to modules/sekindoUMBidAdapter.js index f6c3d423742..ec73cb16a6e 100755 --- a/src/adapters/sekindoUM.js +++ b/modules/sekindoUMBidAdapter.js @@ -1,29 +1,26 @@ -import { getBidRequest } from '../utils.js'; -var CONSTANTS = require('../constants.json'); -var utils = require('../utils.js'); -var bidfactory = require('../bidfactory.js'); -var bidmanager = require('../bidmanager.js'); -var adloader = require('../adloader.js'); +import { getBidRequest } from 'src/utils.js'; +var CONSTANTS = require('src/constants.json'); +var utils = require('src/utils.js'); +var bidfactory = require('src/bidfactory.js'); +var bidmanager = require('src/bidmanager.js'); +var adloader = require('src/adloader.js'); +var adaptermanager = require('src/adaptermanager'); var sekindoUMAdapter; sekindoUMAdapter = function sekindoUMAdapter() { - function _callBids(params) { var bids = params.bids; var bidsCount = bids.length; var pubUrl = null; - if (parent !== window) - pubUrl = document.referrer; - else - pubUrl = window.location.href; + if (parent !== window) { pubUrl = document.referrer; } else { pubUrl = window.location.href; } for (var i = 0; i < bidsCount; i++) { var bidReqeust = bids[i]; var callbackId = bidReqeust.bidId; _requestBids(bidReqeust, callbackId, pubUrl); - //store a reference to the bidRequest from the callback id - //bidmanager.pbCallbackMap[callbackId] = bidReqeust; + // store a reference to the bidRequest from the callback id + // bidmanager.pbCallbackMap[callbackId] = bidReqeust; } } @@ -36,7 +33,6 @@ sekindoUMAdapter = function sekindoUMAdapter() { var placementCode = bidObj.placementCode; if (response.cpm !== undefined && response.cpm > 0) { - bid = bidfactory.createBid(CONSTANTS.STATUS.GOOD); bid.callback_uid = callbackId; bid.bidderCode = bidCode; @@ -47,35 +43,29 @@ sekindoUMAdapter = function sekindoUMAdapter() { bid.height = response.height; bidmanager.addBidResponse(placementCode, bid); - } - - else { + } else { bid = bidfactory.createBid(CONSTANTS.STATUS.NO_BID); bid.callback_uid = callbackId; bid.bidderCode = bidCode; bidmanager.addBidResponse(placementCode, bid); } } - } - - else { + } else { if (bidObj) { - utils.logMessage('No prebid response for placement '+bidObj.placementCode); - } - - else { + utils.logMessage('No prebid response for placement ' + bidObj.placementCode); + } else { utils.logMessage('sekindoUM callback general error'); } } }; function _requestBids(bid, callbackId, pubUrl) { - //determine tag params + // determine tag params var spaceId = utils.getBidIdParameter('spaceId', bid.params); var subId = utils.getBidIdParameter('subId', bid.params); var bidfloor = utils.getBidIdParameter('bidfloor', bid.params); - var protocol = ('https:' === document.location.protocol ? 's' : ''); - var scriptSrc = 'http'+protocol+'://hb.sekindo.com/live/liveView.php?'; + var protocol = (document.location.protocol === 'https:' ? 's' : ''); + var scriptSrc = 'http' + protocol + '://hb.sekindo.com/live/liveView.php?'; scriptSrc = utils.tryAppendQueryString(scriptSrc, 's', spaceId); scriptSrc = utils.tryAppendQueryString(scriptSrc, 'subId', subId); @@ -95,5 +85,6 @@ sekindoUMAdapter = function sekindoUMAdapter() { }; }; -module.exports = sekindoUMAdapter; +adaptermanager.registerBidAdapter(new sekindoUMAdapter(), 'sekindoUM'); +module.exports = sekindoUMAdapter; diff --git a/src/adapters/serverbid.js b/modules/serverbidBidAdapter.js similarity index 83% rename from src/adapters/serverbid.js rename to modules/serverbidBidAdapter.js index 74b731bbe3f..cd912db367d 100644 --- a/src/adapters/serverbid.js +++ b/modules/serverbidBidAdapter.js @@ -1,52 +1,50 @@ -import Adapter from 'src/adapters/adapter'; +import Adapter from 'src/adapter'; import bidfactory from 'src/bidfactory'; import bidmanager from 'src/bidmanager'; import * as utils from 'src/utils'; import { ajax } from 'src/ajax'; +import adaptermanager from 'src/adaptermanager'; const ServerBidAdapter = function ServerBidAdapter() { - const baseAdapter = Adapter.createNew('serverbid'); const BASE_URI = '//e.serverbid.com/api/v2'; const sizeMap = [null, - "120x90", - "120x90", - "468x60", - "728x90", - "300x250", - "160x600", - "120x600", - "300x100", - "180x150", - "336x280", - "240x400", - "234x60", - "88x31", - "120x60", - "120x240", - "125x125", - "220x250", - "250x250", - "250x90", - "0x0", - "200x90", - "300x50", - "320x50", - "320x480", - "185x185", - "620x45", - "300x125", - "800x250" + '120x90', + '120x90', + '468x60', + '728x90', + '300x250', + '160x600', + '120x600', + '300x100', + '180x150', + '336x280', + '240x400', + '234x60', + '88x31', + '120x60', + '120x240', + '125x125', + '220x250', + '250x250', + '250x90', + '0x0', + '200x90', + '300x50', + '320x50', + '320x480', + '185x185', + '620x45', + '300x125', + '800x250' ]; const bidIds = []; baseAdapter.callBids = function(params) { - if (params && params.bids && utils.isArray(params.bids) && params.bids.length) { - const data = { placements: [], time: Date.now(), @@ -77,19 +75,15 @@ const ServerBidAdapter = function ServerBidAdapter() { if (bid_data.networkId && bid_data.siteId) { data.placements.push(bid_data); } - } if (data.placements.length) { ajax(BASE_URI, _responseCallback, JSON.stringify(data), { method: 'POST', withCredentials: true, contentType: 'application/json' }); } - } - }; function _responseCallback(result) { - let bid; let bidId; let bidObj; @@ -103,7 +97,6 @@ const ServerBidAdapter = function ServerBidAdapter() { } for (let i = 0; i < bidIds.length; i++) { - bidId = bidIds[i]; bidObj = utils.getBidRequest(bidId); bidCode = bidObj.bidder; @@ -124,7 +117,6 @@ const ServerBidAdapter = function ServerBidAdapter() { bid = bidfactory.createBid(2, bidObj); bid.bidderCode = bidCode; } - } else { bid = bidfactory.createBid(2, bidObj); bid.bidderCode = bidCode; @@ -140,7 +132,7 @@ const ServerBidAdapter = function ServerBidAdapter() { function getSize(sizes) { const result = []; sizes.forEach(function(size) { - const index = sizeMap.indexOf(size[0] + "x" + size[1]); + const index = sizeMap.indexOf(size[0] + 'x' + size[1]); if (index >= 0) { result.push(index); } @@ -153,11 +145,12 @@ const ServerBidAdapter = function ServerBidAdapter() { return { callBids: baseAdapter.callBids }; - }; ServerBidAdapter.createNew = function() { return new ServerBidAdapter(); }; -module.exports = ServerBidAdapter; \ No newline at end of file +adaptermanager.registerBidAdapter(new ServerBidAdapter(), 'serverbid'); + +module.exports = ServerBidAdapter; diff --git a/src/adapters/analytics/sharethrough_analytics.js b/modules/sharethroughAnalyticsAdapter.js similarity index 50% rename from src/adapters/analytics/sharethrough_analytics.js rename to modules/sharethroughAnalyticsAdapter.js index 6eadcbcf60c..c805183c058 100644 --- a/src/adapters/analytics/sharethrough_analytics.js +++ b/modules/sharethroughAnalyticsAdapter.js @@ -1,31 +1,32 @@ -import adapter from 'AnalyticsAdapter'; -const utils = require('../../utils'); +import adapter from 'src/AnalyticsAdapter'; +import adaptermanager from 'src/adaptermanager'; +const utils = require('src/utils'); const emptyUrl = ''; const analyticsType = 'endpoint'; -const STR_BIDDER_CODE = "sharethrough"; -const STR_VERSION = "0.1.0"; +const STR_BIDDER_CODE = 'sharethrough'; +const STR_VERSION = '0.1.0'; -export default Object.assign(adapter( +var sharethroughAdapter = Object.assign(adapter( { emptyUrl, analyticsType } ), - { - STR_BEACON_HOST: document.location.protocol + "//b.sharethrough.com/butler?", +{ + STR_BEACON_HOST: document.location.protocol + '//b.sharethrough.com/butler?', placementCodeSet: {}, track({ eventType, args }) { - if(eventType === 'bidRequested' && args.bidderCode === 'sharethrough') { + if (eventType === 'bidRequested' && args.bidderCode === 'sharethrough') { var bids = args.bids; var keys = Object.keys(bids); - for(var i = 0; i < keys.length; i++) { + for (var i = 0; i < keys.length; i++) { this.placementCodeSet[bids[keys[i]].placementCode] = args.bids[keys[i]]; } } - if(eventType === 'bidWon') { + if (eventType === 'bidWon') { this.bidWon(args); } }, @@ -33,18 +34,18 @@ export default Object.assign(adapter( bidWon(args) { const curBidderCode = args.bidderCode; - if(curBidderCode !== STR_BIDDER_CODE && (args.adUnitCode in this.placementCodeSet)) { + if (curBidderCode !== STR_BIDDER_CODE && (args.adUnitCode in this.placementCodeSet)) { let strBid = this.placementCodeSet[args.adUnitCode]; - this.fireLoseBeacon(curBidderCode, args.cpm, strBid.adserverRequestId, "headerBidLose"); + this.fireLoseBeacon(curBidderCode, args.cpm, strBid.adserverRequestId, 'headerBidLose'); } }, fireLoseBeacon(winningBidderCode, winningCPM, arid, type) { let loseBeaconUrl = this.STR_BEACON_HOST; - loseBeaconUrl = utils.tryAppendQueryString(loseBeaconUrl, "winnerBidderCode", winningBidderCode); - loseBeaconUrl = utils.tryAppendQueryString(loseBeaconUrl, "winnerCpm", winningCPM); - loseBeaconUrl = utils.tryAppendQueryString(loseBeaconUrl, "arid", arid); - loseBeaconUrl = utils.tryAppendQueryString(loseBeaconUrl, "type", type); + loseBeaconUrl = utils.tryAppendQueryString(loseBeaconUrl, 'winnerBidderCode', winningBidderCode); + loseBeaconUrl = utils.tryAppendQueryString(loseBeaconUrl, 'winnerCpm', winningCPM); + loseBeaconUrl = utils.tryAppendQueryString(loseBeaconUrl, 'arid', arid); + loseBeaconUrl = utils.tryAppendQueryString(loseBeaconUrl, 'type', type); loseBeaconUrl = this.appendEnvFields(loseBeaconUrl); this.fireBeacon(loseBeaconUrl); @@ -61,3 +62,10 @@ export default Object.assign(adapter( img.src = theUrl; } }); + +adaptermanager.registerAnalyticsAdapter({ + adapter: sharethroughAdapter, + code: 'sharethrough' +}); + +export default sharethroughAdapter; diff --git a/src/adapters/sharethrough.js b/modules/sharethroughBidAdapter.js similarity index 84% rename from src/adapters/sharethrough.js rename to modules/sharethroughBidAdapter.js index 2ca68d16cd3..8bdc7fec551 100644 --- a/src/adapters/sharethrough.js +++ b/modules/sharethroughBidAdapter.js @@ -1,16 +1,16 @@ -var utils = require('../utils.js'); -var bidmanager = require('../bidmanager.js'); -var bidfactory = require('../bidfactory.js'); -var ajax = require('../ajax.js').ajax; +var utils = require('src/utils.js'); +var bidmanager = require('src/bidmanager.js'); +var bidfactory = require('src/bidfactory.js'); +var ajax = require('src/ajax.js').ajax; +var adaptermanager = require('src/adaptermanager'); -const STR_BIDDER_CODE = "sharethrough"; -const STR_VERSION = "1.2.0"; +const STR_BIDDER_CODE = 'sharethrough'; +const STR_VERSION = '1.2.0'; var SharethroughAdapter = function SharethroughAdapter() { - const str = {}; - str.STR_BTLR_HOST = document.location.protocol + "//btlr.sharethrough.com"; - str.STR_BEACON_HOST = document.location.protocol + "//b.sharethrough.com/butler?"; + str.STR_BTLR_HOST = document.location.protocol + '//btlr.sharethrough.com'; + str.STR_BEACON_HOST = document.location.protocol + '//b.sharethrough.com/butler?'; str.placementCodeSet = {}; str.ajax = ajax; @@ -37,7 +37,7 @@ var SharethroughAdapter = function SharethroughAdapter() { let host = str.STR_BTLR_HOST; - let url = host + "/header-bid/v1?"; + let url = host + '/header-bid/v1?'; url = utils.tryAppendQueryString(url, 'bidId', bid.bidId); url = utils.tryAppendQueryString(url, 'placement_key', pkey); url = appendEnvFields(url); @@ -100,10 +100,11 @@ var SharethroughAdapter = function SharethroughAdapter() { return { callBids: _callBids, - str : str, - callback: _strcallback + str: str, }; }; +adaptermanager.registerBidAdapter(new SharethroughAdapter(), 'sharethrough'); + module.exports = SharethroughAdapter; diff --git a/src/adapters/smartadserver.js b/modules/smartadserverBidAdapter.js similarity index 59% rename from src/adapters/smartadserver.js rename to modules/smartadserverBidAdapter.js index f35923411bb..d815f69c752 100644 --- a/src/adapters/smartadserver.js +++ b/modules/smartadserverBidAdapter.js @@ -1,12 +1,13 @@ -var utils = require("../utils.js"); -var bidfactory = require("../bidfactory.js"); -var bidmanager = require("../bidmanager.js"); -var adloader = require("src/adloader.js"); -var url = require("url"); +var utils = require('src/utils.js'); +var bidfactory = require('src/bidfactory.js'); +var bidmanager = require('src/bidmanager.js'); +var adloader = require('src/adloader.js'); +var url = require('src/url.js'); +var adaptermanager = require('src/adaptermanager'); var SmartAdServer = function SmartAdServer() { var generateCallback = function(bid) { - var callbackId = "sas_" + utils.getUniqueIdentifierStr(); + var callbackId = 'sas_' + utils.getUniqueIdentifierStr(); $$PREBID_GLOBAL$$[callbackId] = function(adUnit) { var bidObject; if (adUnit) { @@ -35,17 +36,18 @@ var SmartAdServer = function SmartAdServer() { for (var i = 0; i < params.bids.length; i++) { var bid = params.bids[i]; var adCall = url.parse(bid.params.domain); - adCall.pathname = "/prebid"; + adCall.pathname = '/prebid'; adCall.search = { - "pbjscbk": "pbjs." + generateCallback(bid), - "siteid": bid.params.siteId, - "pgid": bid.params.pageId, - "fmtid": bid.params.formatId, - "ccy": bid.params.currency || "USD", - "tgt": encodeURIComponent(bid.params.target || ''), - "tag": bid.placementCode, - "sizes": bid.sizes.map(size => size[0] + "x" + size[1]).join(","), - "async": 1 + 'pbjscbk': '$$PREBID_GLOBAL$$.' + generateCallback(bid), + 'siteid': bid.params.siteId, + 'pgid': bid.params.pageId, + 'fmtid': bid.params.formatId, + 'ccy': bid.params.currency || 'USD', + 'bidfloor': bid.params.bidfloor || 0.0, + 'tgt': encodeURIComponent(bid.params.target || ''), + 'tag': bid.placementCode, + 'sizes': bid.sizes.map(size => size[0] + 'x' + size[1]).join(','), + 'async': 1 }; adloader.loadScript(url.format(adCall)); } @@ -53,4 +55,6 @@ var SmartAdServer = function SmartAdServer() { }; }; +adaptermanager.registerBidAdapter(new SmartAdServer(), 'smartadserver'); + module.exports = SmartAdServer; diff --git a/src/adapters/smartyads.js b/modules/smartyadsBidAdapter.js similarity index 86% rename from src/adapters/smartyads.js rename to modules/smartyadsBidAdapter.js index 2f2ce8c28ad..36742dc0ddb 100755 --- a/src/adapters/smartyads.js +++ b/modules/smartyadsBidAdapter.js @@ -1,9 +1,10 @@ -import * as Adapter from './adapter.js'; +import * as Adapter from 'src/adapter.js'; import bidfactory from 'src/bidfactory'; import bidmanager from 'src/bidmanager'; import * as utils from 'src/utils'; import {ajax} from 'src/ajax'; import {STATUS} from 'src/constants'; +import adaptermanager from 'src/adaptermanager'; const SMARTYADS_BIDDER_CODE = 'smartyads'; @@ -44,9 +45,7 @@ var sizeMap = { utils._each(sizeMap, (item, key) => sizeMap[item] = key); function SmartyadsAdapter() { - function _callBids(bidderRequest) { - var bids = bidderRequest.bids || []; bids.forEach((bid) => { @@ -57,18 +56,17 @@ function SmartyadsAdapter() { } function bidCallback(responseText) { - try { utils.logMessage('XHR callback function called for ad ID: ' + bid.bidId); handleRpCB(responseText, bid); } catch (err) { - if (typeof err === "string") { + if (typeof err === 'string') { utils.logWarn(`${err} when processing smartyads response for placement code ${bid.placementCode}`); } else { utils.logError('Error processing smartyads response for placement code ' + bid.placementCode, null, err); } - //indicate that there is no bid for this placement + // indicate that there is no bid for this placement let badBid = bidfactory.createBid(STATUS.NO_BID, bid); badBid.bidderCode = bid.bidder; badBid.error = err; @@ -79,7 +77,6 @@ function SmartyadsAdapter() { } function buildOptimizedCall(bid) { - bid.startTime = new Date().getTime(); // use smartyads sizes if provided, otherwise adUnit.sizes @@ -88,7 +85,7 @@ function SmartyadsAdapter() { ); if (parsedSizes.length < 1) { - throw "no valid sizes"; + throw 'no valid sizes'; } var secure; @@ -109,27 +106,25 @@ function SmartyadsAdapter() { 'size_ad', parsedSizes[0], 'alt_size_ad', parsedSizes.slice(1).join(',') || undefined, 'host', host, - "page", page, - "language", language, - "deviceWidth", deviceWidth, - "deviceHeight", deviceHeight, - "secure", secure, - "bidId", bid.bidId, - "checkOn", 'rf' + 'page', page, + 'language', language, + 'deviceWidth', deviceWidth, + 'deviceHeight', deviceHeight, + 'secure', secure, + 'bidId', bid.bidId, + 'checkOn', 'rf' ]; return queryString.reduce( (memo, curr, index) => - index % 2 === 0 && queryString[index + 1] !== undefined ? - memo + curr + '=' + encodeURIComponent(queryString[index + 1]) + '&' + index % 2 === 0 && queryString[index + 1] !== undefined + ? memo + curr + '=' + encodeURIComponent(queryString[index + 1]) + '&' : memo, '//ssp-nj.webtradehub.com/?' ).slice(0, -1); - } function handleRpCB(responseText, bidRequest) { - let ad = JSON.parse(responseText); // can throw var bid = bidfactory.createBid(STATUS.GOOD, bidRequest); @@ -144,14 +139,13 @@ function SmartyadsAdapter() { bidmanager.addBidResponse(bidRequest.placementCode, bid); } - return Object.assign(Adapter.createNew(SMARTYADS_BIDDER_CODE), { // SMARTYADS_BIDDER_CODE smartyads + return Object.assign(Adapter.createNew(SMARTYADS_BIDDER_CODE), { // SMARTYADS_BIDDER_CODE smartyads callBids: _callBids, createNew: SmartyadsAdapter.createNew }); } SmartyadsAdapter.masSizeOrdering = function (sizes) { - const MAS_SIZE_PRIORITY = [15, 2, 9]; return utils.parseSizesInput(sizes) @@ -186,4 +180,6 @@ SmartyadsAdapter.createNew = function () { return new SmartyadsAdapter(); }; -module.exports = SmartyadsAdapter; \ No newline at end of file +adaptermanager.registerBidAdapter(new SmartyadsAdapter(), 'smartyads'); + +module.exports = SmartyadsAdapter; diff --git a/src/adapters/sonobi.js b/modules/sonobiBidAdapter.js similarity index 70% rename from src/adapters/sonobi.js rename to modules/sonobiBidAdapter.js index cca84bb8829..81745427742 100644 --- a/src/adapters/sonobi.js +++ b/modules/sonobiBidAdapter.js @@ -1,13 +1,14 @@ -var bidfactory = require('../bidfactory.js'); -var bidmanager = require('../bidmanager.js'); -var adloader = require('../adloader.js'); -var utils = require('../utils'); +var bidfactory = require('src/bidfactory.js'); +var bidmanager = require('src/bidmanager.js'); +var adloader = require('src/adloader.js'); +var utils = require('src/utils'); +var adaptermanager = require('src/adaptermanager'); -var SonobiAdapter = function SonobiAdapter(){ - var keymakerAssoc = {}; // Remember placement codes for callback mapping - var bidReqAssoc = {}; // Remember bids for bid complete reporting +var SonobiAdapter = function SonobiAdapter() { + var keymakerAssoc = {}; // Remember placement codes for callback mapping + var bidReqAssoc = {}; // Remember bids for bid complete reporting - function _phone_in(request){ + function _phone_in(request) { var trinity = 'https://apex.go.sonobi.com/trinity.js?key_maker='; var adSlots = request.bids || []; var bidderRequestId = request.bidderRequestId; @@ -15,34 +16,34 @@ var SonobiAdapter = function SonobiAdapter(){ adloader.loadScript(trinity + JSON.stringify(_keymaker(adSlots)) + '&cv=' + _operator(bidderRequestId) + ref); } - function _keymaker(adSlots){ + function _keymaker(adSlots) { var keyring = {}; - utils._each(adSlots, function(bidRequest){ - if(bidRequest.params){ + utils._each(adSlots, function(bidRequest) { + if (bidRequest.params) { // Optional var floor = (bidRequest.params.floor) ? bidRequest.params.floor : null; // Mandatory var slotIdentifier = (bidRequest.params.ad_unit) ? bidRequest.params.ad_unit : (bidRequest.params.placement_id) ? bidRequest.params.placement_id : null; var sizes = (bidRequest.params.sizes) ? bidRequest.params.sizes : bidRequest.sizes || null; sizes = utils.parseSizesInput(sizes).toString(); - - if (utils.isEmpty(sizes)){ + + if (utils.isEmpty(sizes)) { utils.logError('Sonobi adapter expects sizes for ' + bidRequest.placementCode); } var bidId = bidRequest.bidId; var args = (sizes) ? ((floor) ? (sizes + '|f=' + floor) : (sizes)) : (floor) ? ('f=' + floor) : ''; - if (/^[\/]?[\d]+[[\/].+[\/]?]?$/.test(slotIdentifier)){ + if (/^[\/]?[\d]+[[\/].+[\/]?]?$/.test(slotIdentifier)) { slotIdentifier = slotIdentifier.charAt(0) === '/' ? slotIdentifier : '/' + slotIdentifier; keyring[slotIdentifier + '|' + bidId] = args; keymakerAssoc[slotIdentifier + '|' + bidId] = bidRequest.placementCode; bidReqAssoc[bidRequest.placementCode] = bidRequest; - } else if (/^[0-9a-fA-F]{20}$/.test(slotIdentifier) && slotIdentifier.length === 20){ + } else if (/^[0-9a-fA-F]{20}$/.test(slotIdentifier) && slotIdentifier.length === 20) { keyring[bidId] = slotIdentifier + '|' + args; keymakerAssoc[bidId] = bidRequest.placementCode; bidReqAssoc[bidRequest.placementCode] = bidRequest; - } else { + } else { keymakerAssoc[bidId] = bidRequest.placementCode; bidReqAssoc[bidRequest.placementCode] = bidRequest; _failure(bidRequest.placementCode); @@ -53,18 +54,18 @@ var SonobiAdapter = function SonobiAdapter(){ return keyring; } - function _operator(bidderRequestId){ - var cb_name = "sbi_" + bidderRequestId; + function _operator(bidderRequestId) { + var cb_name = 'sbi_' + bidderRequestId; window[cb_name] = _trinity; return cb_name; } - function _trinity(response){ + function _trinity(response) { var slots = response.slots || {}; var sbi_dc = response.sbi_dc || ''; - utils._each(slots, function(bid, slot_id){ + utils._each(slots, function(bid, slot_id) { var placementCode = keymakerAssoc[slot_id]; - if (bid.sbi_aid && bid.sbi_mouse && bid.sbi_size){ + if (bid.sbi_aid && bid.sbi_mouse && bid.sbi_size) { _success(placementCode, sbi_dc, bid); } else { _failure(placementCode); @@ -73,15 +74,15 @@ var SonobiAdapter = function SonobiAdapter(){ }); } - function _seraph(placementCode){ + function _seraph(placementCode) { var theOne = bidReqAssoc[placementCode]; delete bidReqAssoc[placementCode]; return theOne; } - function _success(placementCode, sbi_dc, bid){ + function _success(placementCode, sbi_dc, bid) { var goodBid = bidfactory.createBid(1, _seraph(placementCode)); - if(bid.sbi_dozer){ + if (bid.sbi_dozer) { goodBid.dealId = bid.sbi_dozer; } goodBid.bidderCode = 'sonobi'; @@ -92,24 +93,26 @@ var SonobiAdapter = function SonobiAdapter(){ bidmanager.addBidResponse(placementCode, goodBid); } - function _failure(placementCode){ + function _failure(placementCode) { var failBid = bidfactory.createBid(2, _seraph(placementCode)); failBid.bidderCode = 'sonobi'; bidmanager.addBidResponse(placementCode, failBid); } - function _creative(sbi_dc, sbi_aid){ + function _creative(sbi_dc, sbi_aid) { var src = 'https://' + sbi_dc + 'apex.go.sonobi.com/sbi.js?aid=' + sbi_aid + '&as=null'; return ''; } return { - callBids: _phone_in, - formRequest: _keymaker, - parseResponse: _trinity, - success: _success, - failure: _failure + callBids: _phone_in, + formRequest: _keymaker, + parseResponse: _trinity, + success: _success, + failure: _failure }; }; -module.exports = SonobiAdapter; \ No newline at end of file +adaptermanager.registerBidAdapter(new SonobiAdapter(), 'sonobi'); + +module.exports = SonobiAdapter; diff --git a/src/adapters/sovrn.js b/modules/sovrnBidAdapter.js similarity index 79% rename from src/adapters/sovrn.js rename to modules/sovrnBidAdapter.js index 284c458025a..209cdab11d9 100644 --- a/src/adapters/sovrn.js +++ b/modules/sovrnBidAdapter.js @@ -1,8 +1,9 @@ -var CONSTANTS = require('../constants.json'); -var utils = require('../utils.js'); -var bidfactory = require('../bidfactory.js'); -var bidmanager = require('../bidmanager.js'); -var adloader = require('../adloader'); +var CONSTANTS = require('src/constants.json'); +var utils = require('src/utils.js'); +var bidfactory = require('src/bidfactory.js'); +var bidmanager = require('src/bidmanager.js'); +var adloader = require('src/adloader'); +var adaptermanager = require('src/adaptermanager'); /** * Adapter for requesting bids from Sovrn @@ -23,15 +24,15 @@ var SovrnAdapter = function SovrnAdapter() { var sovrnImps = []; - //build impression array for sovrn + // build impression array for sovrn utils._each(bidReqs, function (bid) { var tagId = utils.getBidIdParameter('tagid', bid.params); var bidFloor = utils.getBidIdParameter('bidfloor', bid.params); var adW = 0; var adH = 0; - //sovrn supports only one size per tagid, so we just take the first size if there are more - //if we are a 2 item array of 2 numbers, we must be a SingleSize array + // sovrn supports only one size per tagid, so we just take the first size if there are more + // if we are a 2 item array of 2 numbers, we must be a SingleSize array var bidSizes = Array.isArray(bid.params.sizes) ? bid.params.sizes : bid.sizes; var sizeArrayLength = bidSizes.length; if (sizeArrayLength === 2 && typeof bidSizes[0] === 'number' && typeof bidSizes[1] === 'number') { @@ -43,15 +44,15 @@ var SovrnAdapter = function SovrnAdapter() { } var imp = - { - id: bid.bidId, - banner: { - w: adW, - h: adH - }, - tagid: tagId, - bidfloor: bidFloor - }; + { + id: bid.bidId, + banner: { + w: adW, + h: adH + }, + tagid: tagId, + bidfloor: bidFloor + }; sovrnImps.push(imp); }); @@ -88,7 +89,7 @@ var SovrnAdapter = function SovrnAdapter() { }); } - //expose the callback to the global object: + // expose the callback to the global object: $$PREBID_GLOBAL$$.sovrnResponse = function (sovrnResponseObj) { // valid object? if (sovrnResponseObj && sovrnResponseObj.id) { @@ -96,7 +97,6 @@ var SovrnAdapter = function SovrnAdapter() { if (sovrnResponseObj.seatbid && sovrnResponseObj.seatbid.length !== 0 && sovrnResponseObj.seatbid[0].bid && sovrnResponseObj.seatbid[0].bid.length !== 0) { var impidsWithBidBack = []; sovrnResponseObj.seatbid[0].bid.forEach(function (sovrnBid) { - var responseCPM; var placementCode = ''; var id = sovrnBid.impid; @@ -104,13 +104,13 @@ var SovrnAdapter = function SovrnAdapter() { // try to fetch the bid request we sent Sovrn var bidObj = $$PREBID_GLOBAL$$._bidsRequested.find(bidSet => bidSet.bidderCode === 'sovrn').bids - .find(bid => bid.bidId === id); + .find(bid => bid.bidId === id); if (bidObj) { placementCode = bidObj.placementCode; bidObj.status = CONSTANTS.STATUS.GOOD; - //place ad response on bidmanager._adResponsesByBidderId + // place ad response on bidmanager._adResponsesByBidderId responseCPM = parseFloat(sovrnBid.price); if (responseCPM !== 0) { @@ -121,14 +121,14 @@ var SovrnAdapter = function SovrnAdapter() { // build impression url from response var responseNurl = ''; - //store bid response - //bid status is good (indicating 1) + // store bid response + // bid status is good (indicating 1) bid = bidfactory.createBid(1, bidObj); bid.creative_id = sovrnBid.id; bid.bidderCode = 'sovrn'; bid.cpm = responseCPM; - //set ad content + impression url + // set ad content + impression url // sovrn returns '; + + return divHtml + script; + }; + + var formatOutstreamHTML = function(bid) { + var placementCode = bid.placementCode; + + var config = bid.params; + + // default placement if no placement is set + if (!config.hasOwnProperty('domId') && !config.hasOwnProperty('auto') && !config.hasOwnProperty('p') && !config.hasOwnProperty('article')) { + config.domId = placementCode; + } + + var script = "'; + + return script; + }; + + + function formatAdHTML(bid, size) { + var integrationType = bid.params.format; + + var html = ''; + if (integrationType && integrationType !== 'inbanner') { + html = formatOutstreamHTML(bid); + } else { + html = formatInBannerHTML(bid, size); + } + + return html; + } + + function extractPrice(vast) { + var priceData = vast.getPricing(); + + if (!priceData) { + console.warn("freewheel-ssp: Bid pricing Can't be retreived. You may need to enable pricing on you're zone. Please get in touch with your Freewheel contact."); + } + + return priceData; + } + + function formatBidObject(bidRequest, valid, priceData, html, width, height) { + var bidObject; + if (valid && priceData) { + // valid bid response + bidObject = bidfactory.createBid(1, bidRequest); + bidObject.bidderCode = bidRequest.bidder; + bidObject.cpm = priceData.price; + bidObject.currencyCode = priceData.currency; + bidObject.ad = html; + bidObject.width = width; + bidObject.height = height; + } else { + // invalid bid response + bidObject = bidfactory.createBid(2, bidRequest); + bidObject.bidderCode = bidRequest.bidder; + } + return bidObject; + } + + /** + * returns the top most accessible window + */ + function getTopMostWindow() { + var res = window; + + try { + while (top !== res) { + if (res.parent.location.href.length) { res = res.parent; } + } + } catch (e) {} + + return res; + } + + /* Create a function bound to a given object (assigning `this`, and arguments, + * optionally). Binding with arguments is also known as `curry`. + * Delegates to **ECMAScript 5**'s native `Function.bind` if available. + * We check for `func.bind` first, to fail fast when `func` is undefined. + * + * @param {function} func + * @param {optional} context + * @param {...any} var_args + * @return {function} + */ + var bind = function(func, context) { + return function() { + return func.apply(context, arguments); + }; + }; + + return Object.assign(Adapter.createNew(STICKYADS_BIDDERCODE), { + callBids: _callBids, + formatBidObject: formatBidObject, + formatAdHTML: formatAdHTML, + getBiggerSize: getBiggerSize, + getBid: getBid, + getTopMostWindow: getTopMostWindow, + getComponentId: getComponentId, + getAPIName: getAPIName, + createNew: StickyAdsTVAdapter.createNew // enable alias feature (to be used for freewheel-ssp alias) + }); +}; + +StickyAdsTVAdapter.createNew = function() { + return new StickyAdsTVAdapter(); +}; + +adaptermanager.registerBidAdapter(new StickyAdsTVAdapter(), 'stickyadstv'); +adaptermanager.aliasBidAdapter('stickyadstv', 'freewheel-ssp'); + +module.exports = StickyAdsTVAdapter; diff --git a/src/adapters/tapsense.js b/modules/tapsenseBidAdapter.js similarity index 71% rename from src/adapters/tapsense.js rename to modules/tapsenseBidAdapter.js index f656c580546..a984f6cb8ab 100644 --- a/src/adapters/tapsense.js +++ b/modules/tapsenseBidAdapter.js @@ -1,27 +1,28 @@ -//v0.0.1 +// v0.0.1 -const bidfactory = require('../bidfactory.js'); -const bidmanager = require('../bidmanager.js'); -const adloader = require('../adloader'); -const utils = require('../utils.js'); +const bidfactory = require('src/bidfactory.js'); +const bidmanager = require('src/bidmanager.js'); +const adloader = require('src/adloader'); +const utils = require('src/utils.js'); +const adaptermanager = require('src/adaptermanager'); const TapSenseAdapter = function TapSenseAdapter() { - const version = "0.0.1"; + const version = '0.0.1'; const creativeSizes = [ - "320x50" + '320x50' ]; const validParams = [ - "ufid", - "refer", - "ad_unit_id", //required - "device_id", - "lat", - "long", - "user", //required - "price_floor", - "test" + 'ufid', + 'refer', + 'ad_unit_id', // required + 'device_id', + 'lat', + 'long', + 'user', // required + 'price_floor', + 'test' ]; - const SCRIPT_URL = "https://ads04.tapsense.com/ads/headerad"; + const SCRIPT_URL = 'https://ads04.tapsense.com/ads/headerad'; let bids; $$PREBID_GLOBAL$$.tapsense = {}; function _callBids(params) { @@ -45,19 +46,19 @@ const TapSenseAdapter = function TapSenseAdapter() { let keys = Object.keys(bid.params); for (let j = 0; j < keys.length; j++) { if (validParams.indexOf(keys[j]) < 0) continue; - queryString += encodeURIComponent(keys[j]) + "=" + encodeURIComponent(bid.params[keys[j]]) + "&"; + queryString += encodeURIComponent(keys[j]) + '=' + encodeURIComponent(bid.params[keys[j]]) + '&'; } _requestBids(SCRIPT_URL + queryString); } } } - function generateCallback(bidId){ + function generateCallback(bidId) { return function tapsenseCallback(response, price) { let bidObj; if (response && price) { let bidReq = utils.getBidRequest(bidId); - if (response.status.value === "ok" && response.count_ad_units > 0) { + if (response.status.value === 'ok' && response.count_ad_units > 0) { bidObj = bidfactory.createBid(1, bidObj); bidObj.cpm = price; bidObj.width = response.width; @@ -68,7 +69,6 @@ const TapSenseAdapter = function TapSenseAdapter() { } bidObj.bidderCode = bidReq.bidder; bidmanager.addBidResponse(bidReq.placementCode, bidObj); - } else { utils.logMessage('No prebid response'); } @@ -84,4 +84,6 @@ const TapSenseAdapter = function TapSenseAdapter() { }; }; +adaptermanager.registerBidAdapter(new TapSenseAdapter(), 'tapsense'); + module.exports = TapSenseAdapter; diff --git a/src/adapters/thoughtleadr.js b/modules/thoughtleadrBidAdapter.js similarity index 78% rename from src/adapters/thoughtleadr.js rename to modules/thoughtleadrBidAdapter.js index 2237adb89f5..4e88fd3c6f4 100644 --- a/src/adapters/thoughtleadr.js +++ b/modules/thoughtleadrBidAdapter.js @@ -1,9 +1,10 @@ -"use strict"; -var bidfactory = require("../bidfactory"); -var bidmanager = require("../bidmanager"); -var utils = require('../utils'); -var adloader_1 = require("../adloader"); -var ROOT_URL = "//cdn.thoughtleadr.com/v4/"; +'use strict'; +var bidfactory = require('src/bidfactory'); +var bidmanager = require('src/bidmanager'); +var utils = require('src/utils'); +var adloader_1 = require('src/adloader'); +var adaptermanager = require('src/adaptermanager'); +var ROOT_URL = '//cdn.thoughtleadr.com/v4/'; var BID_AVAILABLE = 1; var ThoughtleadrAdapter = (function () { @@ -16,9 +17,8 @@ var ThoughtleadrAdapter = (function () { if (window.tldr && window.tldr.config && window.tldr.config.root_url) { rootUrl = window.tldr.config.root_url; } - adloader_1.loadScript(rootUrl + "page.js", this.handleBids.bind(this, params), true); - } - else { + adloader_1.loadScript(rootUrl + 'page.js', this.handleBids.bind(this, params), true); + } else { this.handleBids(params); } }; @@ -41,7 +41,7 @@ var ThoughtleadrAdapter = (function () { window.tldr.requestPrebid(bid.params.placementId, rid).then(function (params) { if (!params || !params.bid) { - utils.logError("invalid response from tldr.requestPrebid", undefined, undefined); + utils.logError('invalid response from tldr.requestPrebid', undefined, undefined); return; } @@ -49,10 +49,10 @@ var ThoughtleadrAdapter = (function () { if (ev.origin === location.origin && ev.data && ev.data.TLDR_REQUEST && ev.data.TLDR_REQUEST.rid === rid) { ev.source.postMessage({TLDR_RESPONSE: {config: params.config, rid: rid}}, location.origin); + _this.stopListen(); } - _this.stopListen(); }; - window.addEventListener("message", _this.receiver, false); + window.addEventListener('message', _this.receiver, false); setTimeout(function () { return _this.stopListen(); }, 5000); @@ -65,8 +65,7 @@ var ThoughtleadrAdapter = (function () { bidObject.ad = params.bid.ad; bidObject.width = size.width; bidObject.height = size.height; - } - else { + } else { bidObject = bidfactory.createBid(params.bid.code); bidObject.bidderCode = 'thoughtleadr'; } @@ -76,13 +75,13 @@ var ThoughtleadrAdapter = (function () { ThoughtleadrAdapter.prototype.stopListen = function () { if (this.receiver) { - window.removeEventListener("message", this.receiver); + window.removeEventListener('message', this.receiver); this.receiver = undefined; } }; ThoughtleadrAdapter.valid = function (bid) { - return !!(bid && bid.params && typeof bid.params.placementId === "string"); + return !!(bid && bid.params && typeof bid.params.placementId === 'string'); }; ThoughtleadrAdapter.getSizes = function (sizes) { @@ -98,4 +97,6 @@ var ThoughtleadrAdapter = (function () { return ThoughtleadrAdapter; }()); +adaptermanager.registerBidAdapter(new ThoughtleadrAdapter(), 'thoughtleadr'); + module.exports = ThoughtleadrAdapter; diff --git a/src/adapters/trion.js b/modules/trionBidAdapter.js similarity index 76% rename from src/adapters/trion.js rename to modules/trionBidAdapter.js index 6a0442d0b8f..7535d5dc10e 100644 --- a/src/adapters/trion.js +++ b/modules/trionBidAdapter.js @@ -1,24 +1,22 @@ -import { getBidRequest } from '../utils.js'; - -var CONSTANTS = require('../constants.json'); -var utils = require('../utils.js'); -var adloader = require('../adloader.js'); -var bidmanager = require('../bidmanager.js'); -var bidfactory = require('../bidfactory.js'); -var Adapter = require('./adapter.js'); - -const BID_REQUEST_BASE_URL = "https://in-appadvertising.com/api/bidRequest?"; -const USER_SYNC_URL = "https://in-appadvertising.com/api/userSync.js"; - -var TrionAdapter; -TrionAdapter = function TrionAdapter() { +var CONSTANTS = require('src/constants.json'); +var utils = require('src/utils.js'); +var adloader = require('src/adloader.js'); +var bidmanager = require('src/bidmanager.js'); +var bidfactory = require('src/bidfactory.js'); +var Adapter = require('src/adapter.js'); +var adaptermanager = require('src/adaptermanager'); + +const BID_REQUEST_BASE_URL = 'https://in-appadvertising.com/api/bidRequest?'; +const USER_SYNC_URL = 'https://in-appadvertising.com/api/userSync.js'; + +function TrionAdapter() { var baseAdapter = Adapter.createNew('trion'); var userTag = null; baseAdapter.callBids = function (params) { var bids = params.bids || []; - if(!bids.length){ + if (!bids.length) { return; } @@ -27,10 +25,10 @@ TrionAdapter = function TrionAdapter() { userTag = window.TRION_INT || {}; userTag.pubId = utils.getBidIdParameter('pubId', bids[0].params); userTag.sectionId = utils.getBidIdParameter('sectionId', bids[0].params); - if(!userTag.to){ + if (!userTag.to) { getBids(bids); } - else{ + else { setTimeout(function () { getBids(bids); }, userTag.to); @@ -42,8 +40,8 @@ TrionAdapter = function TrionAdapter() { } }; - function getBids(bids){ - if(!userTag.int_t) { + function getBids(bids) { + if (!userTag.int_t) { userTag.int_t = window.TR_INT_T || -1; } @@ -58,27 +56,28 @@ TrionAdapter = function TrionAdapter() { var pubId = utils.getBidIdParameter('pubId', bid.params); var sectionId = utils.getBidIdParameter('sectionId', bid.params); var re = utils.getBidIdParameter('re', bid.params); - var url = window.location.href; + var url = utils.getTopWindowUrl(); var sizes = utils.parseSizesInput(bid.sizes).join(','); var trionUrl = BID_REQUEST_BASE_URL; - trionUrl = utils.tryAppendQueryString(trionUrl, 'callback', 'pbjs.handleTrionCB'); + trionUrl = utils.tryAppendQueryString(trionUrl, 'callback', '$$PREBID_GLOBAL$$.handleTrionCB'); trionUrl = utils.tryAppendQueryString(trionUrl, 'bidId', bidId); trionUrl = utils.tryAppendQueryString(trionUrl, 'pubId', pubId); trionUrl = utils.tryAppendQueryString(trionUrl, 'sectionId', sectionId); trionUrl = utils.tryAppendQueryString(trionUrl, 're', re); + trionUrl = utils.tryAppendQueryString(trionUrl, 'slot', bid.placementCode); if (url) { trionUrl += 'url=' + url + '&'; } if (sizes) { trionUrl += 'sizes=' + sizes + '&'; } - if(userTag) { + if (userTag) { trionUrl += 'tag=' + encodeURIComponent(JSON.stringify(userTag)) + '&'; } - //remove the trailing "&" + // remove the trailing "&" if (trionUrl.lastIndexOf('&') === trionUrl.length - 1) { trionUrl = trionUrl.substring(0, trionUrl.length - 1); } @@ -86,7 +85,7 @@ TrionAdapter = function TrionAdapter() { return trionUrl; } - //expose the callback to the global object: + // expose the callback to the global object: $$PREBID_GLOBAL$$.handleTrionCB = function (trionResponseObj) { var bid; var bidObj = {}; @@ -97,7 +96,7 @@ TrionAdapter = function TrionAdapter() { var bidId = trionResponseObj.bidId; var result = trionResponseObj && trionResponseObj.result; - bidObj = getBidRequest(bidId); + bidObj = utils.getBidRequest(bidId); if (bidObj) { bidCode = bidObj.bidder; placementCode = bidObj.placementCode; @@ -113,7 +112,7 @@ TrionAdapter = function TrionAdapter() { bid.height = result.height; } } - if(!bid) { + if (!bid) { bid = bidfactory.createBid(CONSTANTS.STATUS.NO_BID, bidObj); } bidmanager.addBidResponse(placementCode, bid); @@ -131,4 +130,6 @@ TrionAdapter.createNew = function () { return new TrionAdapter(); }; +adaptermanager.registerBidAdapter(new TrionAdapter(), 'trion'); + module.exports = TrionAdapter; diff --git a/src/adapters/triplelift.js b/modules/tripleliftBidAdapter.js similarity index 89% rename from src/adapters/triplelift.js rename to modules/tripleliftBidAdapter.js index b629e414dec..1eeb9d32f69 100644 --- a/src/adapters/triplelift.js +++ b/modules/tripleliftBidAdapter.js @@ -1,15 +1,14 @@ -var utils = require('../utils.js'); -var adloader = require('../adloader.js'); -var bidmanager = require('../bidmanager.js'); -var bidfactory = require('../bidfactory.js'); +var utils = require('src/utils.js'); +var adloader = require('src/adloader.js'); +var bidmanager = require('src/bidmanager.js'); +var bidfactory = require('src/bidfactory.js'); +var adaptermanager = require('src/adaptermanager'); /* TripleLift bidder factory function * Use to create a TripleLiftAdapter object */ - var TripleLiftAdapter = function TripleLiftAdapter() { - function _callBids(params) { var tlReq = params.bids; var bidsCount = tlReq.length; @@ -26,9 +25,8 @@ var TripleLiftAdapter = function TripleLiftAdapter() { } } - function buildTLCall(bid, callbackId) { - //determine tag params + // determine tag params var inventoryCode = utils.getBidIdParameter('inventoryCode', bid.params); var floor = utils.getBidIdParameter('floor', bid.params); @@ -99,7 +97,6 @@ var TripleLiftAdapter = function TripleLiftAdapter() { var bid = []; if (tlResponseObj && tlResponseObj.cpm && tlResponseObj.cpm !== 0) { - bid = bidfactory.createBid(1, bidObj); bid.bidderCode = 'triplelift'; bid.cpm = tlResponseObj.cpm; @@ -108,25 +105,21 @@ var TripleLiftAdapter = function TripleLiftAdapter() { bid.height = tlResponseObj.height; bid.dealId = tlResponseObj.deal_id; bidmanager.addBidResponse(placementCode, bid); - } else { // no response data // @if NODE_ENV='debug' - if (bidObj) {utils.logMessage('No prebid response from TripleLift for inventory code: ' + bidObj.params.inventoryCode);} + if (bidObj) { utils.logMessage('No prebid response from TripleLift for inventory code: ' + bidObj.params.inventoryCode); } // @endif bid = bidfactory.createBid(2, bidObj); bid.bidderCode = 'triplelift'; bidmanager.addBidResponse(placementCode, bid); } - } else { // no response data // @if NODE_ENV='debug' utils.logMessage('No prebid response for placement %%PLACEMENT%%'); // @endif - } - }; return { @@ -134,4 +127,7 @@ var TripleLiftAdapter = function TripleLiftAdapter() { }; }; + +adaptermanager.registerBidAdapter(new TripleLiftAdapter(), 'triplelift'); + module.exports = TripleLiftAdapter; diff --git a/src/adapters/twenga.js b/modules/twengaBidAdapter.js similarity index 72% rename from src/adapters/twenga.js rename to modules/twengaBidAdapter.js index a7c844d7dd7..75d01abb2ef 100644 --- a/src/adapters/twenga.js +++ b/modules/twengaBidAdapter.js @@ -1,14 +1,12 @@ -import { getBidRequest } from '../utils.js'; - -var CONSTANTS = require('../constants.json'); -var utils = require('../utils.js'); -var adloader = require('../adloader.js'); -var bidmanager = require('../bidmanager.js'); -var bidfactory = require('../bidfactory.js'); -var Adapter = require('./adapter.js'); - -var TwengaAdapter; -TwengaAdapter = function TwengaAdapter() { +var CONSTANTS = require('src/constants.json'); +var utils = require('src/utils.js'); +var adloader = require('src/adloader.js'); +var bidmanager = require('src/bidmanager.js'); +var bidfactory = require('src/bidfactory.js'); +var Adapter = require('src/adapter.js'); +var adaptermanager = require('src/adaptermanager'); + +function TwengaAdapter() { var baseAdapter = Adapter.createNew('twenga'); baseAdapter.callBids = function (params) { @@ -20,7 +18,6 @@ TwengaAdapter = function TwengaAdapter() { }; function buildBidCall(bid, callbackId) { - var bidUrl = '//rtb.t.c4tw.net/Bid?'; bidUrl = utils.tryAppendQueryString(bidUrl, 's', 'h'); bidUrl = utils.tryAppendQueryString(bidUrl, 'callback', '$$PREBID_GLOBAL$$.handleTwCB'); @@ -30,12 +27,12 @@ TwengaAdapter = function TwengaAdapter() { for (var key in bid.params) { var value = bid.params[key]; switch (key) { - case 'placementId': key = 'id'; break; - case 'siteId': key = 'sid'; break; - case 'publisherId': key = 'pid'; break; - case 'currency': key = 'cur'; break; - case 'bidFloor': key = 'min'; break; - case 'country': key = 'gz'; break; + case 'placementId': key = 'id'; break; + case 'siteId': key = 'sid'; break; + case 'publisherId': key = 'pid'; break; + case 'currency': key = 'cur'; break; + case 'bidFloor': key = 'min'; break; + case 'country': key = 'gz'; break; } bidUrl = utils.tryAppendQueryString(bidUrl, key, value); } @@ -53,25 +50,22 @@ TwengaAdapter = function TwengaAdapter() { // @endif - //append a timer here to track latency + // append a timer here to track latency bid.startTime = new Date().getTime(); return bidUrl; } - //expose the callback to the global object: + // expose the callback to the global object: $$PREBID_GLOBAL$$.handleTwCB = function (bidResponseObj) { - var bidCode; if (bidResponseObj && bidResponseObj.callback_uid) { - var responseCPM; var id = bidResponseObj.callback_uid; var placementCode = ''; - var bidObj = getBidRequest(id); + var bidObj = utils.getBidRequest(id); if (bidObj) { - bidCode = bidObj.bidder; placementCode = bidObj.placementCode; @@ -88,47 +82,41 @@ TwengaAdapter = function TwengaAdapter() { bidResponseObj.result.cpm && bidResponseObj.result.cpm !== 0 && bidResponseObj.result.ad) { - var result = bidResponseObj.result; responseCPM = parseInt(result.cpm, 10); - //CPM response from /Bid is dollar/cent multiplied by 10000 - //in order to avoid using floats - //switch CPM to "dollar/cent" + // CPM response from /Bid is dollar/cent multiplied by 10000 + // in order to avoid using floats + // switch CPM to "dollar/cent" responseCPM = responseCPM / 10000; var ad = result.ad.replace('%%WP%%', result.cpm); - //store bid response - //bid status is good (indicating 1) + // store bid response + // bid status is good (indicating 1) bid = bidfactory.createBid(1, bidObj); bid.creative_id = result.creative_id; bid.bidderCode = bidCode; bid.cpm = responseCPM; - if (ad && (ad.lastIndexOf('http', 0) === 0 || ad.lastIndexOf('//', 0) === 0)) - bid.adUrl = ad; - else - bid.ad = ad; + if (ad && (ad.lastIndexOf('http', 0) === 0 || ad.lastIndexOf('//', 0) === 0)) { bid.adUrl = ad; } else { bid.ad = ad; } bid.width = result.width; bid.height = result.height; bidmanager.addBidResponse(placementCode, bid); - } else { - //no response data + // no response data // @if NODE_ENV='debug' utils.logMessage('No prebid response from Twenga for placement code ' + placementCode); // @endif - //indicate that there is no bid for this placement + // indicate that there is no bid for this placement bid = bidfactory.createBid(2, bidObj); bid.bidderCode = bidCode; bidmanager.addBidResponse(placementCode, bid); } - } else { - //no response data + // no response data // @if NODE_ENV='debug' utils.logMessage('No prebid response for placement %%PLACEMENT%%'); @@ -148,4 +136,6 @@ TwengaAdapter.createNew = function () { return new TwengaAdapter(); }; +adaptermanager.registerBidAdapter(new TwengaAdapter(), 'twenga'); + module.exports = TwengaAdapter; diff --git a/modules/ucfunnelBidAdapter.js b/modules/ucfunnelBidAdapter.js new file mode 100644 index 00000000000..59a3151b1d6 --- /dev/null +++ b/modules/ucfunnelBidAdapter.js @@ -0,0 +1,98 @@ +import * as Adapter from 'src/adapter.js'; +import bidfactory from 'src/bidfactory'; +import bidmanager from 'src/bidmanager'; +import * as utils from 'src/utils'; +import {ajax} from 'src/ajax'; +import {STATUS} from 'src/constants'; +import adaptermanager from 'src/adaptermanager'; + +const VER = 'ADGENT_PREBID-2017051801'; +const UCFUNNEL_BIDDER_CODE = 'ucfunnel'; + +function ucfunnelAdapter() { + function _callBids(params) { + let bids = params.bids || []; + + bids.forEach((bid) => { + try { + ajax(buildOptimizedCall(bid), bidCallback, undefined, { withCredentials: true }); + } catch (err) { + utils.logError('Error sending ucfunnel request for placement code ' + bid.placementCode, null, err); + } + + function bidCallback(responseText) { + try { + utils.logMessage('XHR callback function called for placement code: ' + bid.placementCode); + handleRpCB(responseText, bid); + } catch (err) { + if (typeof err === 'string') { + utils.logWarn(`${err} when processing ucfunnel response for placement code ${bid.placementCode}`); + } else { + utils.logError('Error processing ucfunnel response for placement code ' + bid.placementCode, null, err); + } + + // indicate that there is no bid for this placement + let badBid = bidfactory.createBid(STATUS.NO_BID, bid); + badBid.bidderCode = bid.bidder; + badBid.error = err; + bidmanager.addBidResponse(bid.placementCode, badBid); + } + } + }); + } + + function buildOptimizedCall(bid) { + bid.startTime = new Date().getTime(); + + let host = utils.getTopWindowLocation().host, + page = utils.getTopWindowLocation().pathname, + refer = document.referrer, + language = navigator.language, + dnt = (navigator.doNotTrack == 'yes' || navigator.doNotTrack == '1' || navigator.msDoNotTrack == '1') ? 1 : 0; + + let queryString = [ + 'ifr', 0, + 'bl', language, + 'je', 1, + 'dnt', dnt, + 'host', host, + 'u', page, + 'ru', refer, + 'adid', bid.params.adid, + 'w', bid.params.width, + 'h', bid.params.height, + 'ver', VER + ]; + + return queryString.reduce( + (memo, curr, index) => + index % 2 === 0 && queryString[index + 1] !== undefined + ? memo + curr + '=' + encodeURIComponent(queryString[index + 1]) + '&' + : memo, + '//agent.aralego.com/header?' + ).slice(0, -1); + } + + function handleRpCB(responseText, bidRequest) { + let ad = JSON.parse(responseText); // can throw + + let bid = bidfactory.createBid(STATUS.GOOD, bidRequest); + bid.creative_id = ad.ad_id; + bid.bidderCode = UCFUNNEL_BIDDER_CODE; + bid.cpm = ad.cpm || 0; + bid.ad = ad.adm; + bid.width = ad.width; + bid.height = ad.height; + bid.dealId = ad.deal; + + bidmanager.addBidResponse(bidRequest.placementCode, bid); + } + + return { + callBids: _callBids + }; +}; + +adaptermanager.registerBidAdapter(new ucfunnelAdapter(), UCFUNNEL_BIDDER_CODE); + +module.exports = ucfunnelAdapter; diff --git a/src/adapters/underdogmedia.js b/modules/underdogmediaBidAdapter.js similarity index 81% rename from src/adapters/underdogmedia.js rename to modules/underdogmediaBidAdapter.js index 365e2509555..03c508cf995 100644 --- a/src/adapters/underdogmedia.js +++ b/modules/underdogmediaBidAdapter.js @@ -1,10 +1,10 @@ -var bidfactory = require('../bidfactory.js'); -var bidmanager = require('../bidmanager.js'); -var adloader = require('../adloader.js'); -var utils = require('../utils.js'); - -var UnderdogMediaAdapter = function UnderdogMediaAdapter() { +var bidfactory = require('src/bidfactory.js'); +var bidmanager = require('src/bidmanager.js'); +var adloader = require('src/adloader.js'); +var utils = require('src/utils.js'); +var adaptermanager = require('src/adaptermanager'); +function UnderdogMediaAdapter() { const UDM_ADAPTER_VERSION = '1.0.0'; var getJsStaticUrl = window.location.protocol + '//udmserve.net/udm/img.fetch?tid=1;dt=9;callback=$$PREBID_GLOBAL$$.handleUnderdogMediaCB;'; var bidParams = {}; @@ -18,17 +18,14 @@ var UnderdogMediaAdapter = function UnderdogMediaAdapter() { sizes = utils.flatten(sizes, utils.parseSizesInput(bidParam.sizes)); siteId = bidParam.params.siteId; }); - adloader.loadScript(getJsStaticUrl + "sid=" + siteId + ";sizes=" + sizes.join(","), null, false); + adloader.loadScript(getJsStaticUrl + 'sid=' + siteId + ';sizes=' + sizes.join(','), null, false); } function _callback(response) { - var mids = response.mids; bidParams.bids.forEach(bidParam => { - var filled = false; mids.forEach(mid => { - if (mid.useCount > 0) { return; } @@ -74,13 +71,12 @@ var UnderdogMediaAdapter = function UnderdogMediaAdapter() { $$PREBID_GLOBAL$$.handleUnderdogMediaCB = _callback; function _makeNotification(bid, mid, bidParam) { - var url = mid.notification_url; url += UDM_ADAPTER_VERSION; - url += ";cb=" + Math.random(); - url += ";qqq=" + (1 / bid.cpm); - url += ";hbt=" + $$PREBID_GLOBAL$$.bidderTimeout; + url += ';cb=' + Math.random(); + url += ';qqq=' + (1 / bid.cpm); + url += ';hbt=' + $$PREBID_GLOBAL$$.bidderTimeout; url += ';style=adapter'; url += ';vis=' + encodeURIComponent(document.visibilityState); @@ -88,7 +84,7 @@ var UnderdogMediaAdapter = function UnderdogMediaAdapter() { if (bidParam.params.subId) { url += ';subid=' + encodeURIComponent(bidParam.params.subId); } - return ""; + return ''; } function _getUrlVars() { @@ -109,7 +105,8 @@ var UnderdogMediaAdapter = function UnderdogMediaAdapter() { return { callBids: _callBids }; +} -}; +adaptermanager.registerBidAdapter(new UnderdogMediaAdapter(), 'underdogmedia'); module.exports = UnderdogMediaAdapter; diff --git a/modules/unrulyBidAdapter.js b/modules/unrulyBidAdapter.js new file mode 100644 index 00000000000..208a4b109f3 --- /dev/null +++ b/modules/unrulyBidAdapter.js @@ -0,0 +1,111 @@ +import { ajax } from 'src/ajax' +import bidfactory from 'src/bidfactory' +import bidmanager from 'src/bidmanager' +import * as utils from 'src/utils' +import { STATUS } from 'src/constants' +import { Renderer } from 'src/Renderer' +import adaptermanager from 'src/adaptermanager' + +function createRenderHandler({ bidResponseBid, rendererConfig }) { + function createApi() { + parent.window.unruly.native.prebid = parent.window.unruly.native.prebid || {} + parent.window.unruly.native.prebid.uq = parent.window.unruly.native.prebid.uq || [] + + return { + render(bidResponseBid) { + parent.window.unruly.native.prebid.uq.push(['render', bidResponseBid]) + }, + onLoaded(bidResponseBid) {} + } + } + + parent.window.unruly = parent.window.unruly || {} + parent.window.unruly.native = parent.window.unruly.native || {} + parent.window.unruly.native.siteId = parent.window.unruly.native.siteId || rendererConfig.siteId + + const api = createApi() + return { + render() { + api.render(bidResponseBid) + }, + onRendererLoad() { + api.onLoaded(bidResponseBid) + } + } +} + +function createBidResponseHandler(bidRequestBids) { + return { + onBidResponse(responseBody) { + try { + const exchangeResponse = JSON.parse(responseBody) + exchangeResponse.bids.forEach((exchangeBid) => { + const bidResponseBid = bidfactory.createBid(exchangeBid.ext.statusCode, exchangeBid) + + Object.assign( + bidResponseBid, + exchangeBid + ) + + if (exchangeBid.ext.renderer) { + const rendererParams = exchangeBid.ext.renderer + const renderHandler = createRenderHandler({ + bidResponseBid, + rendererConfig: rendererParams.config + }) + + bidResponseBid.renderer = Renderer.install( + Object.assign( + {}, + rendererParams, + { callback: () => renderHandler.onRendererLoad() } + ) + ) + bidResponseBid.renderer.setRender(() => renderHandler.render()) + } + + bidmanager.addBidResponse(exchangeBid.ext.placementCode, bidResponseBid) + }) + } catch (error) { + utils.logError(error); + bidRequestBids.forEach(bidRequestBid => { + const bidResponseBid = bidfactory.createBid(STATUS.NO_BID) + bidmanager.addBidResponse(bidRequestBid.placementCode, bidResponseBid) + }) + } + } + } +} + +function createUnrulyAdapter() { + const adapter = { + exchangeUrl: 'https://targeting.unrulymedia.com/prebid', + callBids({ bids: bidRequestBids }) { + if (!bidRequestBids || bidRequestBids.length === 0) { + return + } + + const payload = { + bidRequests: bidRequestBids + } + + const bidResponseHandler = createBidResponseHandler(bidRequestBids) + + ajax( + adapter.exchangeUrl, + bidResponseHandler.onBidResponse, + JSON.stringify(payload), + { + contentType: 'application/json', + withCredentials: true + } + ) + } + } + + return adapter +} + +adaptermanager.registerBidAdapter(new createUnrulyAdapter(), 'unruly') + +module.exports = createUnrulyAdapter diff --git a/src/adapters/vertamedia.js b/modules/vertamediaBidAdapter.js similarity index 91% rename from src/adapters/vertamedia.js rename to modules/vertamediaBidAdapter.js index 13f036764d7..3ac68e6d5bd 100644 --- a/src/adapters/vertamedia.js +++ b/modules/vertamediaBidAdapter.js @@ -1,15 +1,16 @@ -import Adapter from 'src/adapters/adapter'; +import Adapter from 'src/adapter'; import bidfactory from 'src/bidfactory'; import bidmanager from 'src/bidmanager'; import * as utils from 'src/utils'; import { ajax } from 'src/ajax'; import { STATUS } from 'src/constants'; +import adaptermanager from 'src/adaptermanager'; const ENDPOINT = '//rtb.vertamedia.com/hb/'; function VertamediaAdapter() { var baseAdapter = Adapter.createNew('vertamedia'), - bidRequest; + bidRequest; baseAdapter.callBids = function (bidRequests) { if (!bidRequests || !bidRequests.bids || bidRequests.bids.length === 0) { @@ -51,7 +52,7 @@ function VertamediaAdapter() { function getSize(requestSizes) { var parsed = {}, - size = utils.parseSizesInput(requestSizes)[0]; + size = utils.parseSizesInput(requestSizes)[0]; if (typeof size !== 'string') { return parsed; @@ -110,11 +111,14 @@ function VertamediaAdapter() { callBids: baseAdapter.callBids, setBidderCode: baseAdapter.setBidderCode }; - } VertamediaAdapter.createNew = function () { return new VertamediaAdapter(); }; +adaptermanager.registerBidAdapter(new VertamediaAdapter(), 'vertamedia', { + supportedMediaTypes: ['video'] +}); + module.exports = VertamediaAdapter; diff --git a/modules/vertozBidAdapter.js b/modules/vertozBidAdapter.js new file mode 100755 index 00000000000..5b758f21603 --- /dev/null +++ b/modules/vertozBidAdapter.js @@ -0,0 +1,71 @@ +var CONSTANTS = require('src/constants.json'); +var utils = require('src/utils.js'); +var bidfactory = require('src/bidfactory.js'); +var bidmanager = require('src/bidmanager.js'); +var adloader = require('src/adloader.js'); +var adaptermanager = require('src/adaptermanager'); + +function VertozAdapter() { + const BASE_URI = '//banner.vrtzads.com/vzhbidder/bid?'; + const BIDDER_NAME = 'vertoz'; + const QUERY_PARAM_KEY = 'q'; + + function _callBids(params) { + var bids = params.bids || []; + + for (var i = 0; i < bids.length; i++) { + var bid = bids[i]; + let slotBidId = utils.getValue(bid, 'bidId'); + let cb = Math.round(new Date().getTime() / 1000); + let vzEndPoint = BASE_URI; + let reqParams = bid.params || {}; + let placementId = utils.getValue(reqParams, 'placementId'); + let cpm = utils.getValue(reqParams, 'cpmFloor'); + + if (utils.isEmptyStr(placementId)) { + utils.logError('missing params:', BIDDER_NAME, 'Enter valid vzPlacementId'); + return; + } + + let reqSrc = utils.getTopWindowLocation().href; + var vzReq = { + _vzPlacementId: placementId, + _rqsrc: reqSrc, + _cb: cb, + _slotBidId: slotBidId, + _cpm: cpm + }; + + let queryParamValue = JSON.stringify(vzReq); + vzEndPoint = utils.tryAppendQueryString(vzEndPoint, QUERY_PARAM_KEY, queryParamValue); + adloader.loadScript(vzEndPoint); + } + } + + $$PREBID_GLOBAL$$.vzResponse = function (vertozResponse) { + var bidRespObj = vertozResponse; + var bidObject; + var reqBidObj = utils.getBidRequest(bidRespObj.slotBidId); + + if (bidRespObj.cpm) { + bidObject = bidfactory.createBid(CONSTANTS.STATUS.GOOD, reqBidObj); + bidObject.cpm = Number(bidRespObj.cpm); + bidObject.ad = bidRespObj.ad + utils.createTrackPixelHtml(decodeURIComponent(bidRespObj.nurl)); + bidObject.width = bidRespObj.adWidth; + bidObject.height = bidRespObj.adHeight; + } else { + let respStatusText = bidRespObj.statusText; + bidObject = bidfactory.createBid(CONSTANTS.STATUS.NO_BID, reqBidObj); + utils.logMessage(respStatusText); + } + + var adSpaceId = reqBidObj.placementCode; + bidObject.bidderCode = BIDDER_NAME; + bidmanager.addBidResponse(adSpaceId, bidObject); + }; + return { callBids: _callBids }; +} + +adaptermanager.registerBidAdapter(new VertozAdapter(), 'vertoz'); + +module.exports = VertozAdapter; diff --git a/src/adapters/wideorbit.js b/modules/wideorbitBidAdapter.js similarity index 87% rename from src/adapters/wideorbit.js rename to modules/wideorbitBidAdapter.js index b9e00ba7a82..19f7e70c1ce 100644 --- a/src/adapters/wideorbit.js +++ b/modules/wideorbitBidAdapter.js @@ -1,16 +1,17 @@ -var bidfactory = require('../bidfactory.js'), - bidmanager = require('../bidmanager.js'), - utils = require('../utils.js'), - adloader = require('../adloader'); +var bidfactory = require('src/bidfactory.js'), + bidmanager = require('src/bidmanager.js'), + utils = require('src/utils.js'), + adloader = require('src/adloader'), + adaptermanager = require('src/adaptermanager'); -var WideOrbitAdapter = function WideOrbitAdapter() { +function WideOrbitAdapter() { var pageImpression = 'JSAdservingMP.ashx?pc={pc}&pbId={pbId}&clk=&exm=&jsv=1.0&tsv=1.0&cts={cts}&arp=0&fl=0&vitp=&vit=&jscb=window.$$PREBID_GLOBAL$$.handleWideOrbitCallback&url={referrer}&fp=&oid=&exr=&mraid=&apid=&apbndl=&mpp=0&uid=&cb={cb}&hb=1', - pageRepeatCommonParam = '&gid{o}={gid}&pp{o}=&clk{o}=&rpos{o}={rpos}&ecpm{o}={ecpm}&ntv{o}=&ntl{o}=&adsid{o}=', - pageRepeatParamId = '&pId{o}={pId}&rank{o}={rank}', - pageRepeatParamNamed = '&wsName{o}={wsName}&wName{o}={wName}&rank{o}={rank}&bfDim{o}={width}x{height}&subp{o}={subp}', - base = (window.location.protocol) + '//p{pbId}.atemda.com/', - bids, - adapterName = 'wideorbit'; + pageRepeatCommonParam = '&gid{o}={gid}&pp{o}=&clk{o}=&rpos{o}={rpos}&ecpm{o}={ecpm}&ntv{o}=&ntl{o}=&adsid{o}=', + pageRepeatParamId = '&pId{o}={pId}&rank{o}={rank}', + pageRepeatParamNamed = '&wsName{o}={wsName}&wName{o}={wName}&rank{o}={rank}&bfDim{o}={width}x{height}&subp{o}={subp}', + base = (window.location.protocol) + '//p{pbId}.atemda.com/', + bids, + adapterName = 'wideorbit'; function _fixParamNames(param) { if (!param) { @@ -18,7 +19,7 @@ var WideOrbitAdapter = function WideOrbitAdapter() { } var properties = ['site', 'page', 'width', 'height', 'rank', 'subPublisher', 'ecpm', 'atf', 'pId', 'pbId', 'referrer'], - prop; + prop; utils._each(properties, function (correctName) { for (prop in param) { @@ -130,7 +131,7 @@ var WideOrbitAdapter = function WideOrbitAdapter() { function _processUserMatchings(userMatchings) { var headElem = document.getElementsByTagName('head')[0], - createdElem; + createdElem; utils._each(userMatchings, function (userMatching) { createdElem = undefined; @@ -165,7 +166,7 @@ var WideOrbitAdapter = function WideOrbitAdapter() { } function _isUrl(scr) { - return scr.slice(0, 6) === "http:/" || scr.slice(0, 7) === "https:/" || scr.slice(0, 2) === "//"; + return scr.slice(0, 6) === 'http:/' || scr.slice(0, 7) === 'https:/' || scr.slice(0, 2) === '//'; } function _buildAdCode(placement) { @@ -213,6 +214,8 @@ var WideOrbitAdapter = function WideOrbitAdapter() { return { callBids: _callBids }; -}; +} + +adaptermanager.registerBidAdapter(new WideOrbitAdapter(), 'wideorbit'); module.exports = WideOrbitAdapter; diff --git a/src/adapters/widespace.js b/modules/widespaceBidAdapter.js similarity index 72% rename from src/adapters/widespace.js rename to modules/widespaceBidAdapter.js index ac44d50fd18..068f948081b 100644 --- a/src/adapters/widespace.js +++ b/modules/widespaceBidAdapter.js @@ -1,27 +1,26 @@ -import { getBidRequest } from '../utils.js'; - -const utils = require('../utils.js'); -const adloader = require('../adloader.js'); -const bidmanager = require('../bidmanager.js'); -const bidfactory = require('../bidfactory.js'); +const utils = require('src/utils.js'); +const adloader = require('src/adloader.js'); +const bidmanager = require('src/bidmanager.js'); +const bidfactory = require('src/bidfactory.js'); +const adaptermanager = require('src/adaptermanager'); const WS_ADAPTER_VERSION = '1.0.2'; function WidespaceAdapter() { - let useSSL = 'https:' === document.location.protocol, - baseURL = (useSSL ? 'https:' : 'http:') + '//engine.widespace.com/map/engine/hb/dynamic?', - callbackName = '$$PREBID_GLOBAL$$.widespaceHandleCB'; + let useSSL = document.location.protocol === 'https:', + baseURL = (useSSL ? 'https:' : 'http:') + '//engine.widespace.com/map/engine/hb/dynamic?', + callbackName = '$$PREBID_GLOBAL$$.widespaceHandleCB'; function _callBids(params) { let bids = params && params.bids || []; for (var i = 0; i < bids.length; i++) { const bid = bids[i], - callbackUid = bid.bidId, - sid = bid.params.sid, - currency = bid.params.cur || bid.params.currency; + callbackUid = bid.bidId, + sid = bid.params.sid, + currency = bid.params.cur || bid.params.currency; - //Handle Sizes string + // Handle Sizes string let sizeQueryString = ''; let parsedSizes = utils.parseSizesInput(bid.sizes); @@ -58,21 +57,21 @@ function WidespaceAdapter() { } } - //Handle our callback + // Handle our callback var handleCallback = function handleCallback(bidsArray) { if (!bidsArray) { return; } var bidObject, - bidCode = 'widespace'; + bidCode = 'widespace'; for (var i = 0, l = bidsArray.length; i < l; i++) { var bid = bidsArray[i], - placementCode = '', - validSizes = []; + placementCode = '', + validSizes = []; bid.sizes = {height: bid.height, width: bid.width}; - var inBid = getBidRequest(bid.callbackUid); + var inBid = utils.getBidRequest(bid.callbackUid); if (inBid) { bidCode = inBid.bidder; @@ -80,7 +79,7 @@ function WidespaceAdapter() { validSizes = inBid.sizes; } - if (bid && bid.callbackUid && bid.status !=='noad' && verifySize(bid.sizes, validSizes)) { + if (bid && bid.callbackUid && bid.status !== 'noad' && verifySize(bid.sizes, validSizes)) { bidObject = bidfactory.createBid(1); bidObject.bidderCode = bidCode; bidObject.cpm = bid.cpm; @@ -113,4 +112,6 @@ function WidespaceAdapter() { }; } +adaptermanager.registerBidAdapter(new WidespaceAdapter(), 'widespace'); + module.exports = WidespaceAdapter; diff --git a/modules/xhbBidAdapter.js b/modules/xhbBidAdapter.js new file mode 100644 index 00000000000..186a0dfd4b8 --- /dev/null +++ b/modules/xhbBidAdapter.js @@ -0,0 +1,171 @@ +import * as Adapter from 'src/adapter'; +import bidfactory from 'src/bidfactory'; +import bidmanager from 'src/bidmanager'; +import * as utils from 'src/utils'; +import { STATUS } from 'src/constants'; +import adaptermanager from 'src/adaptermanager'; +import { loadScript } from 'src/adloader'; + +const XhbAdapter = function XhbAdapter() { + const baseAdapter = Adapter.createNew('xhb'); + let usersync = false; + + const _defaultBidderSettings = { + alwaysUseBid: true, + adserverTargeting: [ + { + key: 'hb_xhb_deal', + val: function (bidResponse) { + return bidResponse.adId; + } + }, + { + key: 'hb_xhb_adid', + val: function (bidResponse) { + return bidResponse.adId; + } + } + ] + }; + bidmanager.registerDefaultBidderSetting('xhb', _defaultBidderSettings); + + baseAdapter.callBids = function (params) { + const anArr = params.bids; + for (let i = 0; i < anArr.length; i++) { + let bidRequest = anArr[i]; + let callbackId = bidRequest.bidId; + loadScript(buildJPTCall(bidRequest, callbackId)); + } + }; + + function buildJPTCall(bid, callbackId) { + // determine tag params + const placementId = utils.getBidIdParameter('placementId', bid.params); + const member = utils.getBidIdParameter('member', bid.params); + const inventoryCode = utils.getBidIdParameter('invCode', bid.params); + let referrer = utils.getBidIdParameter('referrer', bid.params); + const altReferrer = utils.getBidIdParameter('alt_referrer', bid.params); + + // Build tag, always use https + let jptCall = 'https://ib.adnxs.com/jpt?'; + + jptCall = utils.tryAppendQueryString(jptCall, 'callback', '$$PREBID_GLOBAL$$.handleXhbCB'); + jptCall = utils.tryAppendQueryString(jptCall, 'callback_uid', callbackId); + jptCall = utils.tryAppendQueryString(jptCall, 'id', placementId); + jptCall = utils.tryAppendQueryString(jptCall, 'psa', '0'); + jptCall = utils.tryAppendQueryString(jptCall, 'member', member); + jptCall = utils.tryAppendQueryString(jptCall, 'code', inventoryCode); + jptCall = utils.tryAppendQueryString(jptCall, 'traffic_source_code', (utils.getBidIdParameter('trafficSourceCode', bid.params))); + + // sizes takes a bit more logic + let sizeQueryString = ''; + let parsedSizes = utils.parseSizesInput(bid.sizes); + + // combine string into proper querystring for impbus + let parsedSizesLength = parsedSizes.length; + if (parsedSizesLength > 0) { + // first value should be "size" + sizeQueryString = 'size=' + parsedSizes[0]; + if (parsedSizesLength > 1) { + // any subsequent values should be "promo_sizes" + sizeQueryString += '&promo_sizes='; + for (let j = 1; j < parsedSizesLength; j++) { + sizeQueryString += parsedSizes[j] += ','; + } + // remove trailing comma + if (sizeQueryString && sizeQueryString.charAt(sizeQueryString.length - 1) === ',') { + sizeQueryString = sizeQueryString.slice(0, sizeQueryString.length - 1); + } + } + } + + if (sizeQueryString) { + jptCall += sizeQueryString + '&'; + } + + // append referrer + if (referrer === '') { + referrer = utils.getTopWindowUrl(); + } + + jptCall = utils.tryAppendQueryString(jptCall, 'referrer', referrer); + jptCall = utils.tryAppendQueryString(jptCall, 'alt_referrer', altReferrer); + + // remove the trailing "&" + if (jptCall.lastIndexOf('&') === jptCall.length - 1) { + jptCall = jptCall.substring(0, jptCall.length - 1); + } + + return jptCall; + } + + // expose the callback to the global object: + $$PREBID_GLOBAL$$.handleXhbCB = function (jptResponseObj) { + let bidCode; + + if (jptResponseObj && jptResponseObj.callback_uid) { + let responseCPM; + const id = jptResponseObj.callback_uid; + let placementCode = ''; + const bidObj = getBidRequest(id); + if (bidObj) { + bidCode = bidObj.bidder; + placementCode = bidObj.placementCode; + + // set the status + bidObj.status = STATUS.GOOD; + } + + let bid = []; + if (jptResponseObj.result && jptResponseObj.result.ad && jptResponseObj.result.ad !== '') { + responseCPM = 0.00; + + // store bid response + // bid status is good (indicating 1) + let adId = jptResponseObj.result.creative_id; + bid = bidfactory.createBid(STATUS.GOOD, bidObj); + bid.creative_id = adId; + bid.bidderCode = bidCode; + bid.cpm = responseCPM; + bid.adUrl = jptResponseObj.result.ad; + bid.width = jptResponseObj.result.width; + bid.height = jptResponseObj.result.height; + bid.dealId = '99999999'; + + bidmanager.addBidResponse(placementCode, bid); + } else { + // no response data + // indicate that there is no bid for this placement + bid = bidfactory.createBid(STATUS.NO_BID, bidObj); + bid.bidderCode = bidCode; + bidmanager.addBidResponse(placementCode, bid); + } + + if (!usersync) { + let iframe = utils.createInvisibleIframe(); + iframe.src = '//acdn.adnxs.com/ib/static/usersync/v3/async_usersync.html'; + try { + document.body.appendChild(iframe); + } catch (error) { + utils.logError(error); + } + usersync = true; + } + } + }; + + return { + callBids: baseAdapter.callBids, + setBidderCode: baseAdapter.setBidderCode, + createNew: XhbAdapter.createNew, + buildJPTCall: buildJPTCall + }; +}; + +XhbAdapter.createNew = function () { + return new XhbAdapter(); +}; + +adaptermanager.registerBidAdapter(new XhbAdapter(), 'xhb'); + +module.exports = XhbAdapter; diff --git a/src/adapters/yieldbot.js b/modules/yieldbotBidAdapter.js similarity index 76% rename from src/adapters/yieldbot.js rename to modules/yieldbotBidAdapter.js index 65ce539c596..f6dd99b593a 100644 --- a/src/adapters/yieldbot.js +++ b/modules/yieldbotBidAdapter.js @@ -2,10 +2,11 @@ * @overview Yieldbot sponsored Prebid.js adapter. * @author elljoh */ -var adloader = require('../adloader'); -var bidfactory = require('../bidfactory'); -var bidmanager = require('../bidmanager'); -var utils = require('../utils'); +var adloader = require('src/adloader'); +var bidfactory = require('src/bidfactory'); +var bidmanager = require('src/bidmanager'); +var utils = require('src/utils'); +var adaptermanager = require('src/adaptermanager'); /** * Adapter for requesting bids from Yieldbot. @@ -13,8 +14,7 @@ var utils = require('../utils'); * @returns {Object} Object containing implementation for invocation in {@link module:adaptermanger.callBids} * @class */ -var YieldbotAdapter = function YieldbotAdapter() { - +function YieldbotAdapter() { window.ybotq = window.ybotq || []; var ybotlib = { @@ -47,7 +47,6 @@ var YieldbotAdapter = function YieldbotAdapter() { var bid = {}; if (slotCriteria && slotCriteria.ybot_ad && slotCriteria.ybot_ad !== 'n') { - bid = bidfactory.createBid(ybotlib.BID_STATUS.AVAILABLE); bid.cpm = parseInt(slotCriteria.ybot_cpm) / 100.0 || 0; // Yieldbot CPM bids are in cents @@ -65,7 +64,6 @@ var YieldbotAdapter = function YieldbotAdapter() { for (var k in slotCriteria) { bid[k] = slotCriteria[k]; } - } else { bid = bidfactory.createBid(ybotlib.BID_STATUS.EMPTY); } @@ -79,7 +77,6 @@ var YieldbotAdapter = function YieldbotAdapter() { * @private */ callBids: function (params) { - var bids = params.bids || []; var ybotq = window.ybotq || []; @@ -87,24 +84,37 @@ var YieldbotAdapter = function YieldbotAdapter() { ybotq.push(function () { var yieldbot = window.yieldbot; - + // Empty defined slots bidId array ybotlib.definedSlots = []; + // Iterate through bids to obtain Yieldbot slot config + // - Slot config can be different between initial and refresh requests + var psn = 'ERROR_PREBID_DEFINE_YB_PSN'; + var slots = {}; utils._each(bids, function (v) { var bid = v; - var psn = bid.params && bid.params.psn || 'ERROR_DEFINE_YB_PSN'; - var slot = bid.params && bid.params.slot || 'ERROR_DEFINE_YB_SLOT'; + // bidder params config: http://prebid.org/dev-docs/bidders/yieldbot.html + // - last psn wins + psn = bid.params && bid.params.psn || psn; + var slotName = bid.params && bid.params.slot || 'ERROR_PREBID_DEFINE_YB_SLOT'; - yieldbot.pub(psn); - yieldbot.defineSlot(slot, { sizes: bid.sizes || [] }); + slots[slotName] = bid.sizes || []; ybotlib.definedSlots.push(bid.bidId); }); - yieldbot.enableAsync(); + if (yieldbot._initialized !== true) { + yieldbot.pub(psn); + for (var slotName in slots) { + if (slots.hasOwnProperty(slotName)) { + yieldbot.defineSlot(slotName, { sizes: slots[slotName] || [] }); + } + } + yieldbot.enableAsync(); yieldbot.go(); } else { - yieldbot.nextPageview(); + yieldbot.nextPageview(slots); } }); + ybotq.push(function () { ybotlib.handleUpdateState(); }); @@ -123,7 +133,7 @@ var YieldbotAdapter = function YieldbotAdapter() { var adapterConfig; ybRequest = $$PREBID_GLOBAL$$._bidsRequested - .find(bidderRequest => bidderRequest.bidderCode === 'yieldbot'); + .find(bidderRequest => bidderRequest.bidderCode === 'yieldbot'); adapterConfig = ybRequest && ybRequest.bids ? ybRequest.bids.find(bid => bid.bidId === v) : null; @@ -140,6 +150,8 @@ var YieldbotAdapter = function YieldbotAdapter() { return { callBids: ybotlib.callBids }; -}; +} + +adaptermanager.registerBidAdapter(new YieldbotAdapter(), 'yieldbot'); module.exports = YieldbotAdapter; diff --git a/package.json b/package.json index b6764249d44..a6aeb505df0 100644 --- a/package.json +++ b/package.json @@ -1,10 +1,11 @@ { "name": "prebid.js", - "version": "0.23.1", + "version": "0.26.1", "description": "Header Bidding Management Library", "main": "src/prebid.js", "scripts": { - "test": "gulp test && gulp mocha" + "test": "gulp run-tests", + "lint": "gulp lint" }, "repository": { "type": "git", @@ -23,9 +24,12 @@ "url": "http://www.aolplatforms.com/" }], "license": "Apache-2.0", + "engines": { + "node": ">=4.0" + }, "devDependencies": { "babel-core": "6.22.0", - "babel-loader": "6.4.1", + "babel-loader": "^7.1.1", "babel-plugin-transform-es3-member-expression-literals": "6.22.0", "babel-plugin-transform-es3-property-literals": "6.22.0", "babel-preset-es2015": "6.22.0", @@ -35,52 +39,54 @@ "del": "^2.2.0", "ejs": "^2.5.1", "es5-shim": "^4.5.2", + "eslint-config-standard": "^10.2.1", + "eslint-plugin-import": "^2.2.0", + "eslint-plugin-node": "^5.1.0", + "eslint-plugin-promise": "^3.5.0", + "eslint-plugin-standard": "^3.0.1", "faker": "^3.1.0", "fs.extra": "^1.3.2", "gulp": "^3.8.7", "gulp-babel": "^6.1.2", - "gulp-clean": "^0.3.1", + "gulp-clean": "^0.3.2", "gulp-concat": "^2.6.0", - "gulp-connect": "^2.0.6", + "gulp-connect": "^5.0.0", + "gulp-eslint": "^4.0.0", + "gulp-footer": "^1.0.5", "gulp-header": "^1.7.1", - "gulp-jscs": "^3.0.2", + "gulp-if": "^2.0.2", "gulp-jsdoc-to-markdown": "^1.2.1", - "gulp-jshint": "^1.8.4", - "gulp-karma": "0.0.4", - "gulp-mocha": "^2.2.0", "gulp-optimize-js": "^1.1.0", "gulp-rename": "^1.2.0", "gulp-replace": "^0.4.0", "gulp-shell": "^0.5.2", - "gulp-uglify": "^0.3.1", + "gulp-uglify": "^3.0.0", "gulp-util": "^3.0.0", "gulp-webdriver": "^1.0.1", - "gulp-zip": "^3.1.0", - "istanbul": "^0.3.2", - "istanbul-instrumenter-loader": "^0.1.2", - "jshint-stylish": "^2.2.1", + "istanbul": "^0.4.5", + "istanbul-instrumenter-loader": "^2.0.0", "json-loader": "^0.5.1", - "karma": "^0.13.2", + "karma": "^1.7.0", "karma-babel-preprocessor": "^6.0.1", "karma-browserstack-launcher": "^1.0.1", "karma-chai": "^0.1.0", - "karma-chrome-launcher": "^0.2.0", - "karma-coverage": "^0.2.7", + "karma-chrome-launcher": "^2.2.0", + "karma-coverage-istanbul-reporter": "^1.3.0", "karma-es5-shim": "^0.0.4", "karma-expect": "^1.1.0", - "karma-firefox-launcher": "^0.1.3", - "karma-html-reporter": "^0.2.7", - "karma-ie-launcher": "^0.1.5", - "karma-junit-reporter": "^0.3.8", + "karma-firefox-launcher": "^1.0.1", + "karma-ie-launcher": "^1.0.0", + "karma-junit-reporter": "^1.2.0", "karma-mocha": "^0.2.0", - "karma-opera-launcher": "^0.1.0", - "karma-phantomjs-launcher": "^0.2.1", - "karma-requirejs": "^0.2.2", - "karma-safari-launcher": "^0.1.1", - "karma-sauce-launcher": "^0.2.10", - "karma-script-launcher": "^0.1.0", - "karma-sinon-ie": "^2.0.0-rc10", - "karma-webpack": "^1.5.1", + "karma-opera-launcher": "^1.0.0", + "karma-requirejs": "^1.1.0", + "karma-safari-launcher": "^1.0.0", + "karma-sauce-launcher": "^1.1.0", + "karma-script-launcher": "^1.0.0", + "karma-sinon-ie": "^2.0.0", + "karma-sourcemap-loader": "^0.3.7", + "karma-spec-reporter": "^0.0.31", + "karma-webpack": "^2.0.3", "localtunnel": "^1.3.0", "lodash": "^4.17.4", "mkpath": "^1.0.0", @@ -88,20 +94,21 @@ "mock-fs": "^3.11.0", "nightwatch": "^0.9.5", "open": "0.0.5", - "phantomjs": "^1.9.18", "proxyquire": "^1.7.10", "querystringify": "0.0.3", "requirejs": "^2.1.20", "sinon": "^1.12.1", - "string-replace-webpack-plugin": "0.0.3", + "string-replace-webpack-plugin": "^0.1.3", + "through2": "^2.0.3", "uglify-js": "^2.8.10", "url-parse": "^1.0.5", - "webpack": "^1.12.3", - "webpack-stream": "^3.1.0", + "webpack": "^3.0.0", + "webpack-stream": "^3.2.0", "yargs": "^1.3.1" }, "dependencies": { "babel-plugin-transform-object-assign": "^6.22.0", - "core-js": "^2.4.1" + "core-js": "^2.4.1", + "gulp-sourcemaps": "^2.6.0" } } diff --git a/plugins/RequireEnsureWithoutJsonp.js b/plugins/RequireEnsureWithoutJsonp.js new file mode 100644 index 00000000000..b3b38f5e336 --- /dev/null +++ b/plugins/RequireEnsureWithoutJsonp.js @@ -0,0 +1,30 @@ +/** + * RequireEnsureWithoutJsonp + * + * This plugin redefines the behavior of require.ensure that is used by webpack to load chunks. Usually require.ensure + * includes code that allows the asynchronous loading of webpack chunks through jsonp requests AND includes a manifest + * of all the build chunks so that they can be requested by name (e.g. require.ensure('./module.js'). Since that + * functionality is not required and we plan on loading all of our chunks manually (either by concatenating all the + * files together or including as individual scripts) we don't want the overhead of including that loading code or the + * file manifest. In this plugin, that code is replaced with an error message if a module is requested that hasn't been + * loaded manually. + * + * @constructor + */ +function RequireEnsureWithoutJsonp() {} +RequireEnsureWithoutJsonp.prototype.apply = function(compiler) { + compiler.plugin('compilation', function(compilation) { + compilation.mainTemplate.plugin('require-ensure', function(_, chunk, hash) { + return ( +` +if(installedChunks[chunkId] === 0) + return callback.call(null, __webpack_require__); +else + console.error('webpack chunk not found and jsonp disabled'); +` + ).trim(); + }); + }); +}; + +module.exports = RequireEnsureWithoutJsonp; diff --git a/src/adapters/analytics/AnalyticsAdapter.js b/src/AnalyticsAdapter.js similarity index 87% rename from src/adapters/analytics/AnalyticsAdapter.js rename to src/AnalyticsAdapter.js index 2c177621047..8f8a4b12551 100644 --- a/src/adapters/analytics/AnalyticsAdapter.js +++ b/src/AnalyticsAdapter.js @@ -1,9 +1,9 @@ -import CONSTANTS from 'src/constants.json'; -import { loadScript } from 'src/adloader'; -import { ajax } from 'src/ajax'; +import CONSTANTS from './constants'; +import { loadScript } from './adloader'; +import { ajax } from './ajax'; -const events = require('src/events'); -const utils = require('../../utils'); +const events = require('./events'); +const utils = require('./utils'); const AUCTION_INIT = CONSTANTS.EVENTS.AUCTION_INIT; const AUCTION_END = CONSTANTS.EVENTS.AUCTION_END; @@ -83,7 +83,7 @@ export default function AnalyticsAdapter({ url, analyticsType, global, handler } if (_sampled) { - //first send all events fired before enableAnalytics called + // first send all events fired before enableAnalytics called events.getEvents().forEach(event => { if (!event) { return; @@ -98,17 +98,17 @@ export default function AnalyticsAdapter({ url, analyticsType, global, handler } } }); - //Next register event listeners to send data immediately + // Next register event listeners to send data immediately _handlers = { [BID_REQUESTED]: args => this.enqueue({ eventType: BID_REQUESTED, args }), - [BID_RESPONSE]: args => this.enqueue({ eventType: BID_RESPONSE, args }), + [BID_RESPONSE]: args => this.enqueue({ eventType: BID_RESPONSE, args }), [BID_TIMEOUT]: args => this.enqueue({ eventType: BID_TIMEOUT, args }), [BID_WON]: args => this.enqueue({ eventType: BID_WON, args }), [BID_ADJUSTMENT]: args => this.enqueue({ eventType: BID_ADJUSTMENT, args }), [AUCTION_END]: args => this.enqueue({ eventType: AUCTION_END, args }), [AUCTION_INIT]: args => { - args.config = config.options; // enableAnaltyics configuration object + args.config = config.options; // enableAnaltyics configuration object this.enqueue({ eventType: AUCTION_INIT, args }); } }; @@ -139,7 +139,7 @@ export default function AnalyticsAdapter({ url, analyticsType, global, handler } _queue[i](); } - //override push to execute the command immediately from now on + // override push to execute the command immediately from now on _queue.push = function (fn) { fn(); }; diff --git a/src/Renderer.js b/src/Renderer.js index c4e926ca4d5..c532b164fea 100644 --- a/src/Renderer.js +++ b/src/Renderer.js @@ -1,20 +1,38 @@ -import { loadScript } from 'src/adloader'; -import * as utils from 'src/utils'; +import { loadScript } from './adloader'; +import * as utils from './utils'; export function Renderer(options) { - const { url, config, id, callback } = options; + const { url, config, id, callback, loaded } = options; this.url = url; this.config = config; - this.callback = callback; this.handlers = {}; this.id = id; + // a renderer may push to the command queue to delay rendering until the + // render function is loaded by loadScript, at which point the the command + // queue will be processed + this.loaded = loaded; + this.cmd = []; + this.push = func => { + if (typeof func !== 'function') { + utils.logError('Commands given to Renderer.push must be wrapped in a function'); + return; + } + this.loaded ? func.call() : this.cmd.push(func); + }; + + // bidders may override this with the `callback` property given to `install` + this.callback = callback || (() => { + this.loaded = true; + this.process(); + }); + // we expect to load a renderer url once only so cache the request to load script - loadScript(url, callback, true); + loadScript(url, this.callback, true); } -Renderer.install = function({ url, config, id, callback }) { - return new Renderer({ url, config, id, callback }); +Renderer.install = function({ url, config, id, callback, loaded }) { + return new Renderer({ url, config, id, callback, loaded }); }; Renderer.prototype.getConfig = function() { @@ -36,3 +54,17 @@ Renderer.prototype.handleVideoEvent = function({ id, eventName }) { utils.logMessage(`Prebid Renderer event for id ${id} type ${eventName}`); }; + +/* + * Calls functions that were pushed to the command queue before the + * renderer was loaded by `loadScript` + */ +Renderer.prototype.process = function() { + while (this.cmd.length > 0) { + try { + this.cmd.shift().call(); + } catch (error) { + utils.logError('Error processing Renderer command: ', error); + } + } +}; diff --git a/src/adServerManager.js b/src/adServerManager.js new file mode 100644 index 00000000000..a8340431000 --- /dev/null +++ b/src/adServerManager.js @@ -0,0 +1,54 @@ +import { getGlobal } from './prebidGlobal'; +import { logWarn } from './utils'; + +const prebid = getGlobal(); + +/** + * This file defines the plugin points in prebid-core for AdServer-specific functionality. + * + * Its main job is to expose functions for AdServer modules to append functionality to the Prebid public API. + * For a given Ad Server with name "adServerName", these functions will only change the API in the + * $$PREBID_GLOBAL$$.adServers[adServerName] namespace. + */ + +/** + * @typedef {Object} CachedVideoBid + * + * @property {string} videoCacheId The ID which can be used to retrieve this video from prebid-server. + * This is the same ID given to the callback in the videoCache's store function. + */ + +/** + * @function VideoAdUrlBuilder + * + * @param {CachedVideoBid} bid The winning Bid which the ad server should show, assuming it beats out + * the competition. + * + * @param {Object} options Options required by the Ad Server to make a valid AdServer URL. + * This object will have different properties depending on the specific ad server supported. + * For more information, see the docs inside the ad server module you're supporting. + * + * @return {string} A URL which can be passed into the Video player to play an ad. + */ + +/** + * @typedef {Object} VideoSupport + * + * @function {VideoAdUrlBuilder} buildVideoAdUrl + */ + +/** + * Enable video support for the Ad Server. + * + * @property {string} name The identifying name for this adserver. + * @property {VideoSupport} videoSupport An object with the functions needed to support video in Prebid. + */ +export function registerVideoSupport(name, videoSupport) { + prebid.adServers = prebid.adServers || { }; + prebid.adServers[name] = prebid.adServers[name] || { }; + if (prebid.adServers[name].buildVideoUrl) { + logWarn(`Multiple calls to registerVideoSupport for AdServer ${name}. Expect surprising behavior.`); + return; + } + prebid.adServers[name].buildVideoUrl = videoSupport.buildVideoUrl; +} diff --git a/src/adapters/adapter.js b/src/adapter.js similarity index 100% rename from src/adapters/adapter.js rename to src/adapter.js diff --git a/src/adaptermanager.js b/src/adaptermanager.js index 27c5ddca30b..004c8d6fac6 100644 --- a/src/adaptermanager.js +++ b/src/adaptermanager.js @@ -2,17 +2,21 @@ import { flatten, getBidderCodes, shuffle } from './utils'; import { mapSizes } from './sizeMapping'; +import { processNativeAdUnitParams, nativeAdapters } from './native'; var utils = require('./utils.js'); var CONSTANTS = require('./constants.json'); var events = require('./events'); -import { BaseAdapter } from './adapters/baseAdapter'; var _bidderRegistry = {}; exports.bidderRegistry = _bidderRegistry; -//create s2s settings objectType_function -let _s2sConfig = {}; +// create s2s settings objectType_function +let _s2sConfig = { + endpoint: CONSTANTS.S2S.DEFAULT_ENDPOINT, + adapter: CONSTANTS.S2S.ADAPTER, + syncEndpoint: CONSTANTS.S2S.SYNC_ENDPOINT +}; var _analyticsRegistry = {}; let _bidderSequence = null; @@ -28,10 +32,18 @@ function getBids({bidderCode, requestId, bidderRequestId, adUnits}) { } sizes = sizeMapping; } + + if (adUnit.nativeParams) { + bid = Object.assign({}, bid, { + nativeParams: processNativeAdUnitParams(adUnit.nativeParams), + }); + } + return Object.assign({}, bid, { placementCode: adUnit.code, mediaType: adUnit.mediaType, - transactionId : adUnit.transactionId, + renderer: adUnit.renderer, + transactionId: adUnit.transactionId, sizes: sizes, bidId: bid.bid_id || utils.getUniqueIdentifierStr(), bidderRequestId, @@ -49,6 +61,7 @@ exports.callBids = ({adUnits, cbTimeout}) => { const auctionInit = { timestamp: auctionStart, requestId, + timeout: cbTimeout }; events.emit(CONSTANTS.EVENTS.AUCTION_INIT, auctionInit); @@ -57,17 +70,24 @@ exports.callBids = ({adUnits, cbTimeout}) => { bidderCodes = shuffle(bidderCodes); } - if(_s2sConfig.enabled) { - //these are called on the s2s adapter + const s2sAdapter = _bidderRegistry[_s2sConfig.adapter]; + if (s2sAdapter) { + s2sAdapter.setConfig(_s2sConfig); + s2sAdapter.queueSync({bidderCodes}); + } + + + if (_s2sConfig.enabled) { + // these are called on the s2s adapter let adaptersServerSide = _s2sConfig.bidders; - //don't call these client side + // don't call these client side bidderCodes = bidderCodes.filter((elm) => { return !adaptersServerSide.includes(elm); }); let adUnitsCopy = utils.cloneJson(adUnits); - //filter out client side bids + // filter out client side bids adUnitsCopy.forEach((adUnit) => { if (adUnit.sizeMapping) { adUnit.sizes = mapSizes(adUnit); @@ -82,6 +102,11 @@ exports.callBids = ({adUnits, cbTimeout}) => { }); }); + // don't send empty requests + adUnitsCopy = adUnitsCopy.filter(adUnit => { + return adUnit.bids.length !== 0; + }); + let tid = utils.generateUUID(); adaptersServerSide.forEach(bidderCode => { const bidderRequestId = utils.getUniqueIdentifierStr(); @@ -90,19 +115,19 @@ exports.callBids = ({adUnits, cbTimeout}) => { requestId, bidderRequestId, tid, - bids: getBids({bidderCode, requestId, bidderRequestId, 'adUnits' : adUnitsCopy}), + bids: getBids({bidderCode, requestId, bidderRequestId, 'adUnits': adUnitsCopy}), start: new Date().getTime(), auctionStart: auctionStart, - timeout: _s2sConfig.timeout + timeout: _s2sConfig.timeout, + src: CONSTANTS.S2S.SRC }; - //Pushing server side bidder - $$PREBID_GLOBAL$$._bidsRequested.push(bidderRequest); + if (bidderRequest.bids.length !== 0) { + $$PREBID_GLOBAL$$._bidsRequested.push(bidderRequest); + } }); - let s2sBidRequest = {tid, 'ad_units' : adUnitsCopy}; - let s2sAdapter = _bidderRegistry[_s2sConfig.adapter]; //jshint ignore:line + let s2sBidRequest = {tid, 'ad_units': adUnitsCopy}; utils.logMessage(`CALLING S2S HEADER BIDDERS ==== ${adaptersServerSide.join(',')}`); - s2sAdapter.setConfig(_s2sConfig); s2sAdapter.callBids(s2sBidRequest); } @@ -138,24 +163,30 @@ function transformHeightWidth(adUnit) { sizes.forEach(size => { let heightWidth = size.split('x'); let sizeObj = { - 'w' : parseInt(heightWidth[0]), - 'h' : parseInt(heightWidth[1]) + 'w': parseInt(heightWidth[0]), + 'h': parseInt(heightWidth[1]) }; sizesObj.push(sizeObj); }); return sizesObj; } -exports.registerBidAdapter = function (bidAdaptor, bidderCode) { - if (bidAdaptor && bidderCode) { +exports.videoAdapters = []; // added by adapterLoader for now +exports.registerBidAdapter = function (bidAdaptor, bidderCode, {supportedMediaTypes = []} = {}) { + if (bidAdaptor && bidderCode) { if (typeof bidAdaptor.callBids === CONSTANTS.objectType_function) { _bidderRegistry[bidderCode] = bidAdaptor; + if (supportedMediaTypes.includes('video')) { + exports.videoAdapters.push(bidderCode); + } + if (supportedMediaTypes.includes('native')) { + nativeAdapters.push(bidderCode); + } } else { utils.logError('Bidder adaptor error for bidder code: ' + bidderCode + 'bidder must implement a callBids() function'); } - } else { utils.logError('bidAdaptor or bidderCode not specified'); } @@ -172,14 +203,9 @@ exports.aliasBidAdapter = function (bidderCode, alias) { } else { try { let newAdapter = null; - if (bidAdaptor instanceof BaseAdapter) { - //newAdapter = new bidAdaptor.constructor(alias); - utils.logError(bidderCode + ' bidder does not currently support aliasing.', 'adaptermanager.aliasBidAdapter'); - } else { - newAdapter = bidAdaptor.createNew(); - newAdapter.setBidderCode(alias); - this.registerBidAdapter(newAdapter, alias); - } + newAdapter = bidAdaptor.createNew(); + newAdapter.setBidderCode(alias); + this.registerBidAdapter(newAdapter, alias); } catch (e) { utils.logError(bidderCode + ' bidder does not currently support aliasing.', 'adaptermanager.aliasBidAdapter'); } @@ -191,7 +217,6 @@ exports.aliasBidAdapter = function (bidderCode, alias) { exports.registerAnalyticsAdapter = function ({adapter, code}) { if (adapter && code) { - if (typeof adapter.enableAnalytics === CONSTANTS.objectType_function) { adapter.code = code; _analyticsRegistry[code] = adapter; @@ -227,11 +252,3 @@ exports.setBidderSequence = function (order) { exports.setS2SConfig = function (config) { _s2sConfig = config; }; - -/** INSERT ADAPTERS - DO NOT EDIT OR REMOVE */ - -/** END INSERT ADAPTERS */ - -/** INSERT ANALYTICS - DO NOT EDIT OR REMOVE */ - -/** END INSERT ANALYTICS */ diff --git a/src/adapters/aardvark.js b/src/adapters/aardvark.js deleted file mode 100644 index b89a8266ddd..00000000000 --- a/src/adapters/aardvark.js +++ /dev/null @@ -1,144 +0,0 @@ -/* - * Adapter for requesting bids from RTK Aardvark - * To request an RTK Aardvark Header bidding account - * or for additional integration support please contact sales@rtk.io - */ - -var utils = require('../utils.js'); -var bidfactory = require('../bidfactory.js'); -var bidmanager = require('../bidmanager.js'); -var adloader = require('../adloader.js'); -var adapter = require('./adapter.js'); -var constants = require('../constants.json'); - -var AARDVARK_CALLBACK_NAME = 'aardvarkResponse', - AARDVARK_REQUESTS_MAP = 'aardvarkRequests', - AARDVARK_BIDDER_CODE = 'aardvark', - DEFAULT_REFERRER = 'thor.rtk.io', - DEFAULT_ENDPOINT = 'thor.rtk.io', - - endpoint = DEFAULT_ENDPOINT, - - requestBids = function(bidderCode, callbackName, bidReqs) { - var ref = utils.getTopWindowLocation(), - ai = '', - scs = [], - bidIds = []; - - ref = ref ? ref.host : DEFAULT_REFERRER; - - for (var i = 0, l = bidReqs.length, bid, _ai, _sc, _endpoint; i < l; i += 1) { - bid = bidReqs[i]; - _ai = utils.getBidIdParameter('ai', bid.params); - _sc = utils.getBidIdParameter('sc', bid.params); - if (!_ai || !_ai.length || !_sc || !_sc.length) - continue; - - _endpoint = utils.getBidIdParameter('host', bid.params); - if (_endpoint) - endpoint = _endpoint; - - if (!ai.length) - ai = _ai; - if (_sc) - scs.push(_sc); - - bidIds.push(_sc + "=" + bid.bidId); - - // Create the bidIdsMap for easier mapping back later - $$PREBID_GLOBAL$$[AARDVARK_REQUESTS_MAP][bidderCode][bid.bidId] = bid; - } - - if (!ai.length || !scs.length) - return utils.logWarn("Bad bid request params given for adapter $" + bidderCode + " (" + AARDVARK_BIDDER_CODE + ")"); - - adloader.loadScript([ - '//' + endpoint + '/', ai, '/', scs.join('_'), - '/aardvark/?jsonp=$$PREBID_GLOBAL$$.', callbackName, - '&rtkreferer=', ref, '&', bidIds.join('&') - ].join('')); - }, - - - - registerBidResponse = function(bidderCode, rawBidResponse) { - if (rawBidResponse.error) - return utils.logWarn("Aardvark bid received with an error, ignoring... [" + rawBidResponse.error + "]"); - - if (!rawBidResponse.cid) - return utils.logWarn("Aardvark bid received without a callback id, ignoring..."); - - var bidObj = $$PREBID_GLOBAL$$[AARDVARK_REQUESTS_MAP][bidderCode][rawBidResponse.cid]; - if (!bidObj) - return utils.logWarn("Aardvark request not found: " + rawBidResponse.cid); - - if (bidObj.params.sc !== rawBidResponse.id) - return utils.logWarn("Aardvark bid received with a non matching shortcode " + rawBidResponse.id + " instead of " + bidObj.params.sc); - - var bidResponse = bidfactory.createBid(constants.STATUS.GOOD, bidObj); - bidResponse.bidderCode = bidObj.bidder; - bidResponse.cpm = rawBidResponse.cpm; - bidResponse.ad = rawBidResponse.adm + utils.createTrackPixelHtml(decodeURIComponent(rawBidResponse.nurl)); - bidResponse.width = bidObj.sizes[0][0]; - bidResponse.height = bidObj.sizes[0][1]; - - bidmanager.addBidResponse(bidObj.placementCode, bidResponse); - $$PREBID_GLOBAL$$[AARDVARK_REQUESTS_MAP][bidderCode][rawBidResponse.cid].responded = true; - }, - - - - registerAardvarkCallback = function(bidderCode, callbackName) { - $$PREBID_GLOBAL$$[callbackName] = function(rtkResponseObj) { - - rtkResponseObj.forEach(function(bidResponse) { - registerBidResponse(bidderCode, bidResponse); - }); - - for (var bidRequestId in $$PREBID_GLOBAL$$[AARDVARK_REQUESTS_MAP][bidderCode]) - if ($$PREBID_GLOBAL$$[AARDVARK_REQUESTS_MAP][bidderCode].hasOwnProperty(bidRequestId)) { - var bidRequest = $$PREBID_GLOBAL$$[AARDVARK_REQUESTS_MAP][bidderCode][bidRequestId]; - if (!bidRequest.responded) { - var bidResponse = bidfactory.createBid(constants.STATUS.NO_BID, bidRequest); - bidResponse.bidderCode = bidRequest.bidder; - bidmanager.addBidResponse(bidRequest.placementCode, bidResponse); - } - } - }; - }, - - - - AardvarkAdapter = function() { - var baseAdapter = adapter.createNew(AARDVARK_BIDDER_CODE); - - $$PREBID_GLOBAL$$[AARDVARK_REQUESTS_MAP] = $$PREBID_GLOBAL$$[AARDVARK_REQUESTS_MAP] || {}; - - baseAdapter.callBids = function (params) { - var bidderCode = baseAdapter.getBidderCode(), - callbackName = AARDVARK_CALLBACK_NAME; - - if (bidderCode !== AARDVARK_BIDDER_CODE) - callbackName = [AARDVARK_CALLBACK_NAME, bidderCode].join('_'); - - $$PREBID_GLOBAL$$[AARDVARK_REQUESTS_MAP][bidderCode] = {}; - - registerAardvarkCallback(bidderCode, callbackName); - - return requestBids(bidderCode, callbackName, params.bids || []); - }; - - return { - callBids: baseAdapter.callBids, - setBidderCode: baseAdapter.setBidderCode, - createNew: exports.createNew - }; - }; - - - -exports.createNew = function() { - return new AardvarkAdapter(); -}; - -module.exports = AardvarkAdapter; \ No newline at end of file diff --git a/src/adapters/adbutler.js b/src/adapters/adbutler.js deleted file mode 100644 index a0005e89e4f..00000000000 --- a/src/adapters/adbutler.js +++ /dev/null @@ -1,153 +0,0 @@ -/** - * @overview AdButler Prebid.js adapter. - * @author dkharton - */ - -'use strict'; - -var utils = require('../utils.js'); -var adloader = require('../adloader.js'); -var bidmanager = require('../bidmanager.js'); -var bidfactory = require('../bidfactory.js'); - -var AdButlerAdapter = function AdButlerAdapter() { - - function _callBids(params) { - - var bids = params.bids || [], - callbackData = {}, - zoneCount = {}, - pageID = Math.floor(Math.random() * 10e6); - - //Build and send bid requests - for (var i = 0; i < bids.length; i++) { - var bid = bids[i], - zoneID = utils.getBidIdParameter('zoneID', bid.params), - callbackID; - - if(!(zoneID in zoneCount)){ - zoneCount[zoneID] = 0; - } - - //build callbackID to get placementCode later - callbackID = zoneID + '_' +zoneCount[zoneID]; - - callbackData[callbackID] = {}; - callbackData[callbackID].bidId = bid.bidId; - - var adRequest = buildRequest(bid,zoneCount[zoneID],pageID); - zoneCount[zoneID]++; - - adloader.loadScript(adRequest); - } - - //Define callback function for bid responses - $$PREBID_GLOBAL$$.adbutlerCB = function(aBResponseObject){ - - var bidResponse = {}, - callbackID = aBResponseObject.zone_id+'_'+aBResponseObject.place, - width = parseInt(aBResponseObject.width), - height = parseInt(aBResponseObject.height), - isCorrectSize = false, - isCorrectCPM = true, - CPM,minCPM,maxCPM, - bidObj = callbackData[callbackID] ? utils.getBidRequest(callbackData[callbackID].bidId) : null; - - if (bidObj) { - - if(aBResponseObject.status === 'SUCCESS'){ - CPM = aBResponseObject.cpm; - minCPM = utils.getBidIdParameter('minCPM',bidObj.params); - maxCPM = utils.getBidIdParameter('maxCPM',bidObj.params); - - //Ensure response CPM is within the given bounds - if(minCPM !== '' && CPM < parseFloat(minCPM)){ - isCorrectCPM = false; - } - if(maxCPM !== '' && CPM > parseFloat(maxCPM)){ - isCorrectCPM = false; - } - - //Ensure that response ad matches one of the placement sizes. - utils._each(bidObj.sizes,function(size){ - if(width === size[0] && height === size[1]){ - isCorrectSize = true; - } - }); - - if(isCorrectCPM && isCorrectSize){ - - bidResponse = bidfactory.createBid(1,bidObj); - bidResponse.bidderCode = 'adbutler'; - bidResponse.cpm = CPM; - bidResponse.width = width; - bidResponse.height = height; - bidResponse.ad = aBResponseObject.ad_code; - bidResponse.ad += addTrackingPixels(aBResponseObject.tracking_pixels); - - } else { - - bidResponse = bidfactory.createBid(2,bidObj); - bidResponse.bidderCode = 'adbutler'; - - } - } else { - - bidResponse = bidfactory.createBid(2,bidObj); - bidResponse.bidderCode = 'adbutler'; - - } - - bidmanager.addBidResponse(bidObj.placementCode, bidResponse); - - } - }; - } - - function buildRequest(bid,adIndex,pageID){ - var accountID = utils.getBidIdParameter('accountID', bid.params), - zoneID = utils.getBidIdParameter('zoneID', bid.params), - keyword = utils.getBidIdParameter('keyword', bid.params), - domain = utils.getBidIdParameter('domain', bid.params); - - if(typeof domain === 'undefined' || domain.length === 0){ - domain = 'servedbyadbutler.com'; - } - - var requestURI = location.protocol + '//' + domain + '/adserve/;type=hbr;'; - requestURI += 'ID='+encodeURIComponent(accountID)+';'; - requestURI += 'setID='+encodeURIComponent(zoneID)+';'; - requestURI += 'pid='+encodeURIComponent(pageID)+';'; - requestURI += 'place='+encodeURIComponent(adIndex)+';'; - - //append the keyword for targeting if one was passed in - if(keyword !== ''){ - requestURI +='kw='+encodeURIComponent(keyword)+';'; - } - requestURI += 'jsonpfunc=$$PREBID_GLOBAL$$.adbutlerCB;'; - requestURI += 'click=CLICK_MACRO_PLACEHOLDER'; - - return requestURI; - } - - function addTrackingPixels(trackingPixels){ - var trackingPixelMarkup = ''; - utils._each(trackingPixels,function(pixelURL){ - - var trackingPixel = ''; - - trackingPixelMarkup += trackingPixel; - }); - return trackingPixelMarkup; - } - - // Export the callBids function, so that prebid.js can execute this function - // when the page asks to send out bid requests. - return { - callBids: _callBids - }; -}; - -module.exports = AdButlerAdapter; diff --git a/src/adapters/analytics/appnexus.js b/src/adapters/analytics/appnexus.js deleted file mode 100644 index 972fee986ff..00000000000 --- a/src/adapters/analytics/appnexus.js +++ /dev/null @@ -1,12 +0,0 @@ -/** - * appnexus.js - AppNexus Prebid Analytics Adapter - */ - -import adapter from 'AnalyticsAdapter'; - -export default adapter({ - global: 'AppNexusPrebidAnalytics', - handler: 'on', - analyticsType: 'bundle' - }); - diff --git a/src/adapters/analytics/example.js b/src/adapters/analytics/example.js index f79a350630a..37ef0ff8fe3 100644 --- a/src/adapters/analytics/example.js +++ b/src/adapters/analytics/example.js @@ -2,7 +2,7 @@ * example.js - analytics adapter for Example Analytics Library example */ -import adapter from 'AnalyticsAdapter'; +import adapter from '../../AnalyticsAdapter'; export default adapter( { diff --git a/src/adapters/analytics/example2.js b/src/adapters/analytics/example2.js index b9586b5c59a..6888507010d 100644 --- a/src/adapters/analytics/example2.js +++ b/src/adapters/analytics/example2.js @@ -4,7 +4,7 @@ import { ajax } from 'src/ajax'; * example2.js - analytics adapter for Example2 Analytics Endpoint example */ -import adapter from 'AnalyticsAdapter'; +import adapter from '../../AnalyticsAdapter'; const url = 'https://httpbin.org/post'; const analyticsType = 'endpoint'; @@ -15,7 +15,7 @@ export default Object.assign(adapter( analyticsType } ), - { +{ // Override AnalyticsAdapter functions by supplying custom methods track({ eventType, args }) { console.log('track function override for Example2 Analytics'); diff --git a/src/adapters/analytics/libraries/example.js b/src/adapters/analytics/libraries/example.js index e9daf12a5a9..55ef2b8ca45 100644 --- a/src/adapters/analytics/libraries/example.js +++ b/src/adapters/analytics/libraries/example.js @@ -6,9 +6,9 @@ window.ExampleAnalyticsGlobalObject = function(hander, type, data) { window[window.ExampleAnalyticsGlobalObject] = function() {}; -//var utils = require('utils'); -//var events = require('events'); -//var pbjsHandlers = require('prebid-event-handlers'); +// var utils = require('utils'); +// var events = require('events'); +// var pbjsHandlers = require('prebid-event-handlers'); var utils = { errorless: function(fn) { return fn; } }; var events = { init: function() { return arguments; } }; diff --git a/src/adapters/analytics/libraries/example2.js b/src/adapters/analytics/libraries/example2.js index 8cf81bf72aa..913f21177d0 100644 --- a/src/adapters/analytics/libraries/example2.js +++ b/src/adapters/analytics/libraries/example2.js @@ -6,9 +6,9 @@ window.ExampleAnalyticsGlobalObject2 = function(hander, type, data) { window[window.ExampleAnalyticsGlobalObject2] = function() {}; -//var utils = require('utils'); -//var events = require('events'); -//var pbjsHandlers = require('prebid-event-handlers'); +// var utils = require('utils'); +// var events = require('events'); +// var pbjsHandlers = require('prebid-event-handlers'); var utils = { errorless: function(fn) { return fn; } }; var events = { init: function() { return arguments; } }; diff --git a/src/adapters/analytics/pulsepoint.js b/src/adapters/analytics/pulsepoint.js deleted file mode 100644 index 28f4e7f1c78..00000000000 --- a/src/adapters/analytics/pulsepoint.js +++ /dev/null @@ -1,12 +0,0 @@ -/** - * pulsepoint.js - Analytics Adapter for PulsePoint - */ - -import adapter from 'AnalyticsAdapter'; - -export default adapter({ - global: 'PulsePointPrebidAnalytics', - handler: 'on', - analyticsType: 'bundle' - }); - diff --git a/src/adapters/audienceNetwork.js b/src/adapters/audienceNetwork.js deleted file mode 100644 index aafc3bb9edb..00000000000 --- a/src/adapters/audienceNetwork.js +++ /dev/null @@ -1,213 +0,0 @@ -/** - * @file AudienceNetwork adapter. - */ -import { ajax } from '../ajax'; -import { createBid } from '../bidfactory'; -import { addBidResponse } from '../bidmanager'; -import { STATUS } from '../constants.json'; -import { format } from '../url'; -import { logError } from '../utils'; -import { createNew } from './adapter'; - -const { setBidderCode, getBidderCode } = createNew('audienceNetwork'); - -/** - * Does this bid request contain valid parameters? - * @param {Object} bid - * @returns {Boolean} - */ -const validateBidRequest = bid => - typeof bid.params === 'object' && - typeof bid.params.placementId === 'string' && - bid.params.placementId.length > 0 && - Array.isArray(bid.sizes) && bid.sizes.length > 0; - -/** - * Return a copy of a bid with slot sizes flattened and filtered - * @param {Object} bid - * @returns {Object} copy of bid - */ -const flattenBidRequestSizes = bid => { - const sizes = Array.isArray(bid.sizes) && bid.sizes - .map(flattenSize) - .filter(isValidSize); - return Object.assign({}, bid, { sizes }); -}; - -/** - * Flattens a 2-element [W, H] array as a 'WxH' string, - * otherwise passes value through. - * @params {Array|String} size - * @returns {String} - */ -const flattenSize = size => - (Array.isArray(size) && size.length === 2) ? `${size[0]}x${size[1]}` : size; - -/** - * Is this a valid slot size? - * @param {String} size - * @returns {Boolean} - */ -const isValidSize = size => ['native', 'fullwidth', '300x250', '320x50'].includes(size); - -/** - * Does the search part of the URL contain "anhb_testmode" - * and therefore indicate testmode should be used? - * @returns {String} "true" or "false" - */ -const isTestmode = () => Boolean( - window && window.location && - typeof window.location.search === 'string' && - window.location.search.indexOf('anhb_testmode') !== -1 -).toString(); - -/** - * Parse JSON-as-string into an Object, default to empty. - * @param {String} JSON-as-string - * @returns {Object} - */ -const parseJson = jsonAsString => { - let data = {}; - try { - data = JSON.parse(jsonAsString); - } catch (err) {} - return data; -}; - -/** - * Is this a native advert size? - * @param {String} size - * @returns {Boolean} - */ -const isNative = (size) => ['native', 'fullwidth'].includes(size); - -/** - * Generate ad HTML for injection into an iframe - * @param {String} placementId - * @param {String} size - * @param {String} bidId - * @returns {String} HTML - */ -const createAdHtml = (placementId, size, bidId) => { - const nativeStyle = isNative(size) ? '' : ''; - const nativeContainer = isNative(size) ? '
' : ''; - return `${nativeStyle}
- -${nativeContainer}
`; -}; - -/** - * Creates a "good" Bid object with the given bid ID and CPM. - * @param {String} placementId - * @param {String} bidId - * @param {String} size - * @param {Number} cpmCents - * @returns {Object} Bid - */ -const createSuccessBidResponse = (placementId, size, bidId, cpmCents) => { - const bid = createBid(STATUS.GOOD, { bidId }); - // Prebid attributes - bid.bidderCode = getBidderCode(); - bid.cpm = cpmCents / 100; - bid.ad = createAdHtml(placementId, size, bidId); - if (!isNative(size)) { - [bid.width, bid.height] = size.split('x').map(Number); - } - // Audience Network attributes - bid.hb_bidder = 'fan'; - bid.fb_bidid = bidId; - bid.fb_format = size; - bid.fb_placementid = placementId; - return bid; -}; - -/** - * Creates a "no bid" Bid object. - * @returns {Object} Bid - */ -const createFailureBidResponse = () => { - const bid = createBid(STATUS.NO_BID); - bid.bidderCode = getBidderCode(); - return bid; -}; - -/** - * Fetch bids for given parameters. - * @param {Object} bidRequest - * @param {Array} params.bids - list of bids - * @param {String} params.bids[].placementCode - Prebid placement identifier - * @param {Object} params.bids[].params - * @param {String} params.bids[].params.placementId - Audience Network placement identifier - * @param {Array} params.bids[].sizes - list of accepted advert sizes - * @param {Array|String} params.bids[].sizes[] - one of 'native', '300x250', '300x50', [300, 250], [300, 50] - * @returns {void} - */ -const callBids = bidRequest => { - // Build lists of adUnitCodes, placementids and adformats - const adUnitCodes = []; - const placementids = []; - const adformats = []; - bidRequest.bids - .map(flattenBidRequestSizes) - .filter(validateBidRequest) - .forEach( bid => bid.sizes.forEach( size => { - adUnitCodes.push(bid.placementCode); - placementids.push(bid.params.placementId); - adformats.push(size); - })); - - if (placementids.length) { - // Build URL - const testmode = isTestmode(); - const url = format({ - protocol: 'https', - host: 'an.facebook.com', - pathname: '/v2/placementbid.json', - search: { - sdk: '5.5.web', - testmode, - placementids, - adformats - } - }); - // Request - ajax(url, res => { - // Handle response - const data = parseJson(res); - if (data.errors && data.errors.length) { - const noBid = createFailureBidResponse(); - adUnitCodes.forEach( adUnitCode => addBidResponse(adUnitCode, noBid) ); - data.errors.forEach(logError); - } else { - // For each placementId in bids Object - Object.keys(data.bids) - // extract Array of bid responses - .map( placementId => data.bids[placementId] ) - // flatten - .reduce( (a, b) => a.concat(b), [] ) - // call addBidResponse - .forEach( (bid, i) => - addBidResponse(adUnitCodes[i], createSuccessBidResponse( - bid.placement_id, adformats[i], bid.bid_id, bid.bid_price_cents - )) - ); - } - }, null, { withCredentials: true }); - } else { - // No valid bids - logError('No valid bids requested'); - } -}; - -/** - * @class AudienceNetwork - * @type {Object} - * @property {Function} callBids - fetch bids for given parameters - * @property {Function} setBidderCode - used for bidder aliasing - * @property {Function} getBidderCode - unique 'audienceNetwork' identifier - */ -const AudienceNetwork = () => ({ callBids, setBidderCode, getBidderCode }); - -module.exports = AudienceNetwork; diff --git a/src/adapters/baseAdapter.js b/src/adapters/baseAdapter.js deleted file mode 100644 index 819436b4fee..00000000000 --- a/src/adapters/baseAdapter.js +++ /dev/null @@ -1,17 +0,0 @@ -export class BaseAdapter { - constructor(code) { - this.code = code; - } - - getCode() { - return this.code; - } - - setCode(code) { - this.code = code; - } - - callBids() { - throw 'adapter implementation must override callBids method'; - } -} diff --git a/src/adapters/centro.js b/src/adapters/centro.js deleted file mode 100644 index 85303afc823..00000000000 --- a/src/adapters/centro.js +++ /dev/null @@ -1,118 +0,0 @@ -var utils = require('../utils.js'); -var bidfactory = require('../bidfactory.js'); -var bidmanager = require('../bidmanager.js'); -var adloader = require('../adloader'); - -var CentroAdapter = function CentroAdapter() { - var baseUrl = '//t.brand-server.com/hb', - devUrl = '//staging.brand-server.com/hb', - bidderCode = 'centro', - handlerPrefix = 'adCentroHandler_', - - LOG_ERROR_MESS = { - noUnit: 'Bid has no unit', - noAdTag: 'Bid has missmatch format.', - noBid: 'Response has no bid.', - anotherCode: 'Bid has another bidderCode - ', - undefBid: 'Bid is undefined', - unitNum: 'Requested unit is ' - }; - - function _makeHandler(handlerName, unit, placementCode) { - return function(response){ - try { - delete window[handlerName]; - } catch(err) {//catching for old IE - window[handlerName] = undefined; - } - _responseProcessing(response, unit, placementCode); - }; - } - - function _sendBidRequest(bid) { - var placementCode = bid.placementCode, - size = bid.sizes && bid.sizes[0]; - - bid = bid.params; - if (!bid.unit) { - //throw exception, or call utils.logError - utils.logError(LOG_ERROR_MESS.noUnit, bidderCode); - return; - } - var query = ['s=' + bid.unit, 'adapter=prebid'];//,'url=www.abc15.com','sz=320x50']; - var isDev = bid.unit.toString() === '28136'; - - query.push('url=' + encodeURIComponent(bid.page_url || location.href)); - //check size format - if ( - size instanceof Array && - size.length===2 && - typeof size[0] === 'number' && - typeof size[1] === 'number' - ) { - query.push('sz=' + size.join('x')); - } - //make handler name for JSONP request - var handlerName = handlerPrefix + bid.unit + size.join('x') + encodeURIComponent(placementCode); - query.push('callback=' + encodeURIComponent('window["' + handlerName + '"]')); - - //maybe is needed add some random parameter to disable cache - //query.push('r='+Math.round(Math.random() * 1e5)); - - window[handlerName] = _makeHandler(handlerName, bid.unit, placementCode); - - adloader.loadScript((document.location.protocol === 'https:'? 'https:' : 'http:') + (isDev? devUrl : baseUrl) + '?' + query.join('&')); - } - - /* - "sectionID": 7302, - "height": 250, - "width": 300, - "value": 3.2, - "adTag":'' - */ - function _responseProcessing(resp, unit, placementCode) { - var bidObject; - var bid = resp && resp.bid || resp; - - if (bid && bid.adTag && bid.sectionID && bid.sectionID.toString() === unit.toString()) { - bidObject = bidfactory.createBid(1); - bidObject.cpm = bid.value; - bidObject.ad = bid.adTag; - bidObject.width = bid.width; - bidObject.height = bid.height; - } else { - //throw exception, or call utils.logError with resp.statusMessage - utils.logError(LOG_ERROR_MESS.unitNum + unit + '. ' + (bid? bid.statusMessage || LOG_ERROR_MESS.noAdTag : LOG_ERROR_MESS.noBid), bidderCode); - bidObject = bidfactory.createBid(2); - } - bidObject.bidderCode = bidderCode; - bidmanager.addBidResponse(placementCode, bidObject); - } - - /* - { - bidderCode: "centro", - bids: [ - { - unit: '3242432', - page_url: "http://", - size: [300, 250] - */ - function _callBids(params) { - var bid, bids = params.bids || []; - for (var i = 0; i < bids.length; i++) { - bid = bids[i]; - if (bid && bid.bidder === bidderCode) { - _sendBidRequest(bid); - } - } - } - - return { - callBids: _callBids - }; -}; - - -module.exports = CentroAdapter; diff --git a/src/adapters/prebidServer.js b/src/adapters/prebidServer.js deleted file mode 100644 index 7b2c899e905..00000000000 --- a/src/adapters/prebidServer.js +++ /dev/null @@ -1,124 +0,0 @@ -import Adapter from 'src/adapters/adapter'; -import bidfactory from 'src/bidfactory'; -import bidmanager from 'src/bidmanager'; -import * as utils from 'src/utils'; -import { ajax } from 'src/ajax'; -import { STATUS } from 'src/constants'; -import { queueSync, persist } from 'src/cookie.js'; - -const TYPE = 's2s'; -const cookiePersistMessage = `Your browser may be blocking 3rd party cookies. By clicking on this page you allow Prebid Server and other advertising partners to place cookies to help us advertise. You can opt out of their cookies here.`; -const cookiePersistUrl = '//ib.adnxs.com/seg?add=1&redir='; -/** - * Bidder adapter for Prebid Server - */ -function PrebidServer() { - - let baseAdapter = Adapter.createNew('prebidServer'); - let config; - - baseAdapter.setConfig = function(s2sconfig) { - config = s2sconfig; - }; - - /* Prebid executes this function when the page asks to send out bid requests */ - baseAdapter.callBids = function(bidRequest) { - - let requestJson = { - account_id : config.accountId, - tid : bidRequest.tid, - max_bids: config.maxBids, - timeout_millis : config.timeout, - url: utils.getTopWindowUrl(), - prebid_version : '$prebid.version$', - ad_units : bidRequest.ad_units.filter(hasSizes) - }; - - const payload = JSON.stringify(requestJson); - ajax(config.endpoint, handleResponse, payload, { - contentType: 'text/plain', - withCredentials : true - }); - }; - - // at this point ad units should have a size array either directly or mapped so filter for that - function hasSizes(unit) { - return unit.sizes && unit.sizes.length; - } - - /* Notify Prebid of bid responses so bids can get in the auction */ - function handleResponse(response) { - let result; - try { - result = JSON.parse(response); - - if(result.status === 'OK') { - if(result.bidder_status) { - result.bidder_status.forEach(bidder => { - if(bidder.no_bid) { - // store a "No Bid" bid response - - let bidObject = bidfactory.createBid(STATUS.NO_BID, { - bidId: bidder.bid_id - }); - bidObject.adUnitCode = bidder.ad_unit; - bidObject.bidderCode = bidder.bidder; - bidmanager.addBidResponse(bidObject.adUnitCode, bidObject); - } - if(bidder.no_cookie) { - // if no cookie is present then no bids were made, we don't store a bid response - queueSync({bidder: bidder.bidder, url : bidder.usersync.url, type : bidder.usersync.type}); - } - }); - } - if(result.bids) { - result.bids.forEach(bidObj => { - let bidRequest = utils.getBidRequest(bidObj.bid_id); - let cpm = bidObj.price; - let status; - if (cpm !== 0) { - status = STATUS.GOOD; - } else { - status = STATUS.NO_BID; - } - - let bidObject = bidfactory.createBid(status, bidRequest); - bidObject.creative_id = bidObj.creative_id; - bidObject.bidderCode = bidObj.bidder; - bidObject.cpm = cpm; - bidObject.ad = bidObj.adm; - bidObject.width = bidObj.width; - bidObject.height = bidObj.height; - - bidmanager.addBidResponse(bidObj.code, bidObject); - }); - } - } - else if (result.status === 'no_cookie') { - //cookie sync - persist(cookiePersistUrl, cookiePersistMessage); - } - } catch (error) { - utils.logError(error); - } - - if (!result || result.status && result.status.includes('Error')) { - utils.logError('error parsing response: ', result.status); - } - } - - return { - setConfig : baseAdapter.setConfig, - createNew: PrebidServer.createNew, - callBids: baseAdapter.callBids, - setBidderCode: baseAdapter.setBidderCode, - type : TYPE - }; - -} - -PrebidServer.createNew = function() { - return new PrebidServer(); -}; - -module.exports = PrebidServer; diff --git a/src/adapters/pulsepointLite.js b/src/adapters/pulsepointLite.js deleted file mode 100644 index 49900bc2c08..00000000000 --- a/src/adapters/pulsepointLite.js +++ /dev/null @@ -1,90 +0,0 @@ -import {createBid} from 'src/bidfactory'; -import {addBidResponse} from 'src/bidmanager'; -import {logError,getTopWindowLocation} from 'src/utils'; -import {ajax} from 'src/ajax'; -import {STATUS} from 'src/constants'; - -function PulsePointLiteAdapter() { - - const bidUrl = window.location.protocol + '//bid.contextweb.com/header/tag?'; - const ajaxOptions = { - method: 'GET', - withCredentials: true, - contentType: 'text/plain' - }; - - function _callBids(bidderRequest) { - bidderRequest.bids.forEach(bidRequest => { - try { - var params = Object.assign({}, environment(), bidRequest.params); - var url = bidUrl + Object.keys(params).map(k => k + '=' + encodeURIComponent(params[k])).join('&'); - ajax(url, (bidResponse) => { - bidResponseAvailable(bidRequest, bidResponse); - }, null, ajaxOptions); - } catch(e) { - //register passback on any exceptions while attempting to fetch response. - logError('pulsepoint.requestBid', 'ERROR', e); - bidResponseAvailable(bidRequest); - } - }); - } - - function environment() { - return { - cn: 1, - ca: 'BID', - tl: 1, - 'if': 0, - cwu: getTopWindowLocation().href, - cwr: referrer(), - dw: document.documentElement.clientWidth, - cxy: document.documentElement.clientWidth + ',' + document.documentElement.clientHeight, - tz: new Date().getTimezoneOffset(), - ln: (navigator.language || navigator.browserLanguage || navigator.userLanguage || navigator.systemLanguage) - }; - } - - function referrer() { - try { - return window.top.document.referrer; - } catch (e) { - return document.referrer; - } - } - - function bidResponseAvailable(bidRequest, rawResponse) { - if (rawResponse) { - var bidResponse = parse(rawResponse); - if(bidResponse) { - var adSize = bidRequest.params.cf.toUpperCase().split('X'); - var bid = createBid(STATUS.GOOD, bidRequest); - bid.bidderCode = bidRequest.bidder; - bid.cpm = bidResponse.bidCpm; - bid.ad = bidResponse.html; - bid.width = adSize[0]; - bid.height = adSize[1]; - addBidResponse(bidRequest.placementCode, bid); - return; - } - } - var passback = createBid(STATUS.NO_BID, bidRequest); - passback.bidderCode = bidRequest.bidder; - addBidResponse(bidRequest.placementCode, passback); - } - - function parse(rawResponse) { - try { - return JSON.parse(rawResponse); - } catch (ex) { - logError('pulsepoint.safeParse', 'ERROR', ex); - return null; - } - } - - return { - callBids: _callBids - }; - -} - -module.exports = PulsePointLiteAdapter; diff --git a/src/adapters/rhythmone.js b/src/adapters/rhythmone.js deleted file mode 100644 index c8e81d110e3..00000000000 --- a/src/adapters/rhythmone.js +++ /dev/null @@ -1,298 +0,0 @@ -var bidmanager = require('../bidmanager.js'), - bidfactory = require('../bidfactory.js'), - CONSTANTS = require('../constants.json'); - -import {ajax as ajax} from '../ajax'; - -module.exports = function(bidManager, global, loader){ - - var version = "0.9.0.0", - defaultZone = "1r", - defaultPath = "mvo", - debug = false, - requestCompleted = false, - placementCodes = {}, - loadStart, - configuredPlacements = [], - fat = /(^v|(\.0)+$)/gi; - - if(typeof global === "undefined") - global = window; - - if(typeof bidManager === "undefined") - bidManager = bidmanager; - - if(typeof loader === "undefined") - loader = ajax; - - function applyMacros(txt, values){ - return txt.replace(/\{([^\}]+)\}/g, function(match){ - var v = values[match.replace(/[\{\}]/g, "").toLowerCase()]; - if(typeof v !== "undefined") return v; - return match; - }); - } - - function load(bidParams, url, callback){ - loader(url, function(responseText, response){ - if(response.status === 200) - callback(200, "success", response.responseText); - else - callback(-1, "http error "+response.status, response.responseText); - }, false, {method:"GET", withCredentials: true}); - } - - function flashInstalled(){ - var n = global.navigator, - p = n.plugins, - m = n.mimeTypes, - t = "application/x-shockwave-flash", - x = global.ActiveXObject; - - if(p && - p["Shockwave Flash"] && - m && - m[t] && - m[t].enabledPlugin) - return true; - - if(x){ - try{if((new global.ActiveXObject("ShockwaveFlash.ShockwaveFlash"))) return true;} - catch(e){} - } - - return false; - } - - var bidderCode = "rhythmone"; - - function attempt(valueFunction, defaultValue){ - try{ - return valueFunction(); - }catch(ex){} - return defaultValue; - } - - function logToConsole(txt){ - if(debug) - console.log(txt); - } - - function getBidParameters(bids){ - for(var i=0;i 0) - return d[d.length-1]; - return global.top.document.location.hostname; // try/catch is in the attempt function - },"")); - p("title", attempt(function(){return global.top.document.title;},"")); // try/catch is in the attempt function - p("url", attempt(function(){ - var l; - try{l = global.top.document.location.href.toString();} // try/catch is in the attempt function - catch(ex){l = global.document.location.href.toString();} - return l; - },"")); - p("dsh", (global.screen ? global.screen.height : "")); - p("dsw", (global.screen ? global.screen.width : "")); - p("tz", (new Date()).getTimezoneOffset()); - p("dtype", ((/(ios|ipod|ipad|iphone|android)/i).test(global.navigator.userAgent) ? 1 : ((/(smart[-]?tv|hbbtv|appletv|googletv|hdmi|netcast\.tv|viera|nettv|roku|\bdtv\b|sonydtv|inettvbrowser|\btv\b)/i).test(global.navigator.userAgent) ? 3 : 2))); - p("flash", (flashInstalled() ? 1 : 0)); - - var heights = [], - widths = [], - floors = [], - mediaTypes = [], - i=0; - - configuredPlacements = []; - - p("hbv", global.$$PREBID_GLOBAL$$.version.replace(fat,"")+","+version.replace(fat,"")); - - for(; i 0 && typeof bids[i].sizes[0] === "number") - bids[i].sizes = [bids[i].sizes]; - - for(var j = 0; j 0){ - data.ancestor_origins = ao[ao.length-1]; - } - - data.popped = window.opener!==null?1:0; - data.framed = window.top===window?0:1; - - try{ - data.url = window.top.document.location.href.toString(); - }catch(ex){ - data.url = window.document.location.href.toString(); - } - - var prebid_instance = global.$$PREBID_GLOBAL$$; - - data.prebid_version = prebid_instance.version.replace(fat,""); - data.response_ms = (new Date()).getTime() - loadStart; - data.placement_codes = configuredPlacements.join(","); - data.bidder_version = version; - data.prebid_timeout = prebid_instance.cbTimeout || prebid_instance.bidderTimeout; - - for(var k in data){ - q.push(encodeURIComponent(k)+"="+encodeURIComponent((typeof data[k] === "object" ? JSON.stringify(data[k]) : data[k]))); - } - - q.sort(); - i.src = u+q.join("&"); - } - - this.callBids = function(params){ - - var slotMap = {}, - bidParams = getBidParameters(params.bids); - - debug = (bidParams !== null && bidParams.debug === true); - - if(bidParams === null){ - noBids(params); - return; - } - - for(var i = 0; i result[0]*result[1]){ - result = array[i]; - } - } - return result; - } - - var formatInBannerHTML = function(bid,size){ - var placementCode = bid.placementCode; - - var divHtml = "
"; - - var script = ""; - - return divHtml+script; - }; - - var formatIntextHTML = function(bid){ - var placementCode = bid.placementCode; - - var config = bid.params; - - //default placement if no placement is set - if(!config.hasOwnProperty("domId") && !config.hasOwnProperty("auto") && !config.hasOwnProperty("p") && !config.hasOwnProperty("article")){ - config.domId = placementCode; - } - - var script = ""; - - return script; - }; - - var formatScreenRollHTML = function(bid){ - var placementCode = bid.placementCode; - - var config = bid.params; - - var script = ""; - - return script; - }; - - function formatAdHTML(bid, size){ - - var integrationType = bid.params.format; - - var html = ""; - if(integrationType === "intext-roll"){ - html = formatIntextHTML(bid); - } - else if(integrationType === "screen-roll"){ - html = formatScreenRollHTML(bid); - } - else { - html = formatInBannerHTML(bid,size); - } - - return html; - } - - - function extractPrice(vast){ - var priceData = vast.getPricing(); - - if(!priceData) { - console.warn("StickyAdsTV: Bid pricing Can't be retreived. You may need to enable pricing on you're zone. Please get in touch with your sticky contact."); - } - - return priceData; - } - - function formatBidObject(bidRequest, valid, priceData, html, width, height){ - var bidObject; - if(valid && priceData) { - // valid bid response - bidObject = bidfactory.createBid(1, bidRequest); - bidObject.bidderCode = bidRequest.bidder; - bidObject.cpm = priceData.price; - bidObject.currencyCode = priceData.currency; - bidObject.ad = html; - bidObject.width = width; - bidObject.height = height; - - } - else { - // invalid bid response - bidObject = bidfactory.createBid(2, bidRequest); - bidObject.bidderCode = bidRequest.bidder; - } - return bidObject; - } - - - /** - * returns the top most accessible window - */ - function getTopMostWindow(){ - var res=window; - - try { - while(top !== res){ - if(res.parent.location.href.length) - res=res.parent; - } - } - catch(e){} - - return res; - } - - /* Create a function bound to a given object (assigning `this`, and arguments, - * optionally). Binding with arguments is also known as `curry`. - * Delegates to **ECMAScript 5**'s native `Function.bind` if available. - * We check for `func.bind` first, to fail fast when `func` is undefined. - * - * @param {function} func - * @param {optional} context - * @param {...any} var_args - * @return {function} - */ - var bind = function(func, context) { - - return function() { - return func.apply(context,arguments); - }; - }; - - - return Object.assign(Adapter.createNew(STICKYADS_BIDDERCODE), { - callBids: _callBids, - formatBidObject: formatBidObject, - formatAdHTML: formatAdHTML, - getBiggerSize:getBiggerSize, - getBid:getBid, - getTopMostWindow:getTopMostWindow, - createNew: StickyAdsTVAdapter.createNew //enable alias feature (to be used for freewheel-ssp alias) - }); -}; - -StickyAdsTVAdapter.createNew = function() { - return new StickyAdsTVAdapter(); -}; - -module.exports = StickyAdsTVAdapter; \ No newline at end of file diff --git a/src/adapters/vertoz.js b/src/adapters/vertoz.js deleted file mode 100755 index a500f078a92..00000000000 --- a/src/adapters/vertoz.js +++ /dev/null @@ -1,68 +0,0 @@ -var CONSTANTS = require('../constants.json'); -var utils = require('../utils.js'); -var bidfactory = require('../bidfactory.js'); -var bidmanager = require('../bidmanager.js'); -var adloader = require('../adloader.js'); - -var VertozAdapter = function VertozAdapter() { - - const BASE_URI='//banner.vrtzads.com/vzhbidder/bid?'; - const BIDDER_NAME='vertoz'; - const QUERY_PARAM_KEY='q'; - - function _callBids(params) { - var bids = params.bids || []; - - for (var i = 0; i < bids.length; i++) { - var bid = bids[i]; - let slotBidId = utils.getValue(bid,'bidId'); - let cb = Math.round(new Date().getTime() / 1000); - let vzEndPoint = BASE_URI; - let reqParams = bid.params || {}; - let placementId = utils.getValue(reqParams,'placementId'); - - if(utils.isEmptyStr(placementId)){ - utils.logError('missing params:',BIDDER_NAME,'Enter valid vzPlacementId'); - return; - } - - let reqSrc = utils.getTopWindowLocation().href; - var vzReq = { - _vzPlacementId:placementId, - _rqsrc:reqSrc, - _cb:cb, - _slotBidId:slotBidId - }; - let queryParamValue=JSON.stringify(vzReq); - vzEndPoint = utils.tryAppendQueryString(vzEndPoint, QUERY_PARAM_KEY, queryParamValue); - adloader.loadScript(vzEndPoint); - } - - } - - $$PREBID_GLOBAL$$.vzResponse = function (vertozResponse) { - var bidRespObj = vertozResponse; - var bidObject; - var reqBidObj=utils.getBidRequest(bidRespObj.slotBidId); - - if (bidRespObj.cpm) { - bidObject = bidfactory.createBid(CONSTANTS.STATUS.GOOD,reqBidObj); - bidObject.cpm = Number(bidRespObj.cpm); - bidObject.ad = bidRespObj.ad + utils.createTrackPixelHtml(decodeURIComponent(bidRespObj.nurl)); - bidObject.width = bidRespObj.adWidth; - bidObject.height = bidRespObj.adHeight; - }else { - let respStatusText=bidRespObj.statusText; - bidObject = bidfactory.createBid(CONSTANTS.STATUS.NO_BID,reqBidObj); - utils.logMessage(respStatusText); - } - - var adSpaceId = reqBidObj.placementCode; - bidObject.bidderCode = BIDDER_NAME; - bidmanager.addBidResponse(adSpaceId, bidObject); - }; - return { callBids: _callBids }; - -}; - -module.exports = VertozAdapter; diff --git a/src/adapters/xhb.js b/src/adapters/xhb.js deleted file mode 100644 index 2b00844e2a1..00000000000 --- a/src/adapters/xhb.js +++ /dev/null @@ -1,166 +0,0 @@ -import {getBidRequest} from '../utils.js'; - -const CONSTANTS = require('../constants.json'); -const utils = require('../utils.js'); -const adloader = require('../adloader.js'); -const bidmanager = require('../bidmanager.js'); -const bidfactory = require('../bidfactory.js'); - -const XhbAdapter = function XhbAdapter() { - - const _defaultBidderSettings = { - alwaysUseBid: true, - adserverTargeting: [ - { - key: 'hb_xhb_deal', - val: function (bidResponse) { - return bidResponse.dealId; - } - }, - { - key: 'hb_xhb_adid', - val: function (bidResponse) { - return bidResponse.adId; - } - } - ] - }; - bidmanager.registerDefaultBidderSetting('xhb', _defaultBidderSettings); - - function buildJPTCall(bid, callbackId) { - //determine tag params - const placementId = utils.getBidIdParameter('placementId', bid.params); - const inventoryCode = utils.getBidIdParameter('invCode', bid.params); - let referrer = utils.getBidIdParameter('referrer', bid.params); - const altReferrer = utils.getBidIdParameter('alt_referrer', bid.params); - - //Always use https - let jptCall = 'https://ib.adnxs.com/jpt?'; - - jptCall = utils.tryAppendQueryString(jptCall, 'callback', '$$PREBID_GLOBAL$$.handleXhbCB'); - jptCall = utils.tryAppendQueryString(jptCall, 'callback_uid', callbackId); - jptCall = utils.tryAppendQueryString(jptCall, 'id', placementId); - jptCall = utils.tryAppendQueryString(jptCall, 'code', inventoryCode); - - //sizes takes a bit more logic - let sizeQueryString = ''; - let parsedSizes = utils.parseSizesInput(bid.sizes); - - //combine string into proper querystring for impbus - let parsedSizesLength = parsedSizes.length; - if (parsedSizesLength > 0) { - //first value should be "size" - sizeQueryString = 'size=' + parsedSizes[0]; - if (parsedSizesLength > 1) { - //any subsequent values should be "promo_sizes" - sizeQueryString += '&promo_sizes='; - for (let j = 1; j < parsedSizesLength; j++) { - sizeQueryString += parsedSizes[j] += ','; - } - //remove trailing comma - if (sizeQueryString && sizeQueryString.charAt(sizeQueryString.length - 1) === ',') { - sizeQueryString = sizeQueryString.slice(0, sizeQueryString.length - 1); - } - } - } - - if (sizeQueryString) { - jptCall += sizeQueryString + '&'; - } - - //append custom attributes: - let paramsCopy = Object.assign({}, bid.params); - - //delete attributes already used - delete paramsCopy.placementId; - delete paramsCopy.invCode; - delete paramsCopy.query; - delete paramsCopy.referrer; - delete paramsCopy.alt_referrer; - - //get the reminder - let queryParams = utils.parseQueryStringParameters(paramsCopy); - - //append - if (queryParams) { - jptCall += queryParams; - } - - //append referrer - if (referrer === '') { - referrer = utils.getTopWindowUrl(); - } - - jptCall = utils.tryAppendQueryString(jptCall, 'referrer', referrer); - jptCall = utils.tryAppendQueryString(jptCall, 'alt_referrer', altReferrer); - - //remove the trailing "&" - if (jptCall.lastIndexOf('&') === jptCall.length - 1) { - jptCall = jptCall.substring(0, jptCall.length - 1); - } - - return jptCall; - } - - //expose the callback to the global object: - $$PREBID_GLOBAL$$.handleXhbCB = function (jptResponseObj) { - let bidCode; - - if (jptResponseObj && jptResponseObj.callback_uid) { - - let responseCPM; - let id = jptResponseObj.callback_uid; - let placementCode = ''; - let bidObj = getBidRequest(id); - if (bidObj) { - bidCode = bidObj.bidder; - placementCode = bidObj.placementCode; - //set the status - bidObj.status = CONSTANTS.STATUS.GOOD; - } - - let bid = []; - if (jptResponseObj.result && jptResponseObj.result.ad && jptResponseObj.result.ad !== '') { - responseCPM = 0.00; - - //store bid response - //bid status is good (indicating 1) - let adId = jptResponseObj.result.creative_id; - bid = bidfactory.createBid(CONSTANTS.STATUS.GOOD, bidObj); - bid.creative_id = adId; - bid.bidderCode = bidCode; - bid.cpm = responseCPM; - bid.adUrl = jptResponseObj.result.ad; - bid.width = jptResponseObj.result.width; - bid.height = jptResponseObj.result.height; - bid.dealId = '99999999'; - - bidmanager.addBidResponse(placementCode, bid); - - } else { - //no response data - //indicate that there is no bid for this placement - bid = bidfactory.createBid(2); - bid.bidderCode = bidCode; - bidmanager.addBidResponse(placementCode, bid); - } - } - }; - - function _callBids(params) { - let bids = params.bids || []; - for (let i = 0; i < bids.length; i++) { - let bid = bids[i]; - let callbackId = bid.bidId; - adloader.loadScript(buildJPTCall(bid, callbackId)); - } - } - - // Export the callBids function, so that prebid.js can execute - // this function when the page asks to send out bid requests. - return { - callBids: _callBids - }; -}; - -module.exports = XhbAdapter; diff --git a/src/adloader.js b/src/adloader.js index e361d418576..a5c9b3edbe4 100644 --- a/src/adloader.js +++ b/src/adloader.js @@ -1,11 +1,11 @@ var utils = require('./utils'); let _requestCache = {}; -//add a script tag to the page, used to add /jpt call to page +// add a script tag to the page, used to add /jpt call to page exports.loadScript = function (tagSrc, callback, cacheRequest) { - //var noop = () => {}; + // var noop = () => {}; // - //callback = callback || noop; + // callback = callback || noop; if (!tagSrc) { utils.logError('Error attempting to request empty URL', 'adloader.js:loadScript'); return; @@ -15,10 +15,10 @@ exports.loadScript = function (tagSrc, callback, cacheRequest) { if (_requestCache[tagSrc]) { if (callback && typeof callback === 'function') { if (_requestCache[tagSrc].loaded) { - //invokeCallbacks immediately + // invokeCallbacks immediately callback(); } else { - //queue the callback + // queue the callback _requestCache[tagSrc].callbacks.push(callback); } } @@ -45,11 +45,10 @@ exports.loadScript = function (tagSrc, callback, cacheRequest) { } } - //trigger one time request + // trigger one time request else { requestResource(tagSrc, callback); } - }; function requestResource(tagSrc, callback) { @@ -75,7 +74,7 @@ function requestResource(tagSrc, callback) { jptScript.src = tagSrc; - //add the new script tag to the page + // add the new script tag to the page var elToAppend = document.getElementsByTagName('head'); elToAppend = elToAppend.length ? elToAppend : document.getElementsByTagName('body'); if (elToAppend.length) { diff --git a/src/adserver.js b/src/adserver.js index dbdcb0f916b..4346dbeb4a6 100644 --- a/src/adserver.js +++ b/src/adserver.js @@ -1,7 +1,7 @@ import {formatQS} from './url'; import {getWinningBids} from './targeting'; -//Adserver parent class +// Adserver parent class const AdServer = function(attr) { this.name = attr.adserver; this.code = attr.code; @@ -10,16 +10,16 @@ const AdServer = function(attr) { }; }; -//DFP ad server +// DFP ad server exports.dfpAdserver = function (options, urlComponents) { var adserver = new AdServer(options); adserver.urlComponents = urlComponents; var dfpReqParams = { - 'env' : 'vp', - 'gdfp_req' : '1', - 'impl' : 's', - 'unviewed_position_start' : '1' + 'env': 'vp', + 'gdfp_req': '1', + 'impl': 's', + 'unviewed_position_start': '1' }; var dfpParamsWithVariableValue = ['output', 'iu', 'sz', 'url', 'correlator', 'description_url', 'hl']; @@ -38,13 +38,13 @@ exports.dfpAdserver = function (options, urlComponents) { }; adserver.verifyAdserverTag = function() { - for(var key in dfpReqParams) { - if(!this.urlComponents.search.hasOwnProperty(key) || this.urlComponents.search[key] !== dfpReqParams[key]) { + for (var key in dfpReqParams) { + if (!this.urlComponents.search.hasOwnProperty(key) || this.urlComponents.search[key] !== dfpReqParams[key]) { return false; } } - for(var i in dfpParamsWithVariableValue) { - if(!this.urlComponents.search.hasOwnProperty(dfpParamsWithVariableValue[i])) { + for (var i in dfpParamsWithVariableValue) { + if (!this.urlComponents.search.hasOwnProperty(dfpParamsWithVariableValue[i])) { return false; } } diff --git a/src/ajax.js b/src/ajax.js index 42c363dbdf6..cfc7a74b1c2 100644 --- a/src/ajax.js +++ b/src/ajax.js @@ -3,6 +3,7 @@ import {parse as parseURL, format as formatURL} from './url'; var utils = require('./utils'); const XHR_DONE = 4; +let _timeout = 3000; /** * Simple IE9+ and cross-browser ajax request function @@ -13,6 +14,9 @@ const XHR_DONE = 4; * @param data mixed data * @param options object */ +export function setAjaxTimeout(timeout) { + _timeout = timeout; +} export function ajax(url, callback, data, options = {}) { try { @@ -20,7 +24,7 @@ export function ajax(url, callback, data, options = {}) { let useXDomainRequest = false; let method = options.method || (data ? 'POST' : 'GET'); - let callbacks = typeof callback === "object" ? callback : { + let callbacks = typeof callback === 'object' ? callback : { success: function() { utils.logMessage('xhr success'); }, @@ -29,13 +33,13 @@ export function ajax(url, callback, data, options = {}) { } }; - if(typeof callback === "function") { + if (typeof callback === 'function') { callbacks.success = callback; } if (!window.XMLHttpRequest) { useXDomainRequest = true; - } else{ + } else { x = new window.XMLHttpRequest(); if (x.responseType === undefined) { useXDomainRequest = true; @@ -50,10 +54,10 @@ export function ajax(url, callback, data, options = {}) { // http://stackoverflow.com/questions/15786966/xdomainrequest-aborts-post-on-ie-9 x.onerror = function () { - callbacks.error("error", x); + callbacks.error('error', x); }; x.ontimeout = function () { - callbacks.error("timeout", x); + callbacks.error('timeout', x); }; x.onprogress = function() { utils.logMessage('xhr onprogress'); @@ -62,7 +66,7 @@ export function ajax(url, callback, data, options = {}) { x.onreadystatechange = function () { if (x.readyState === XHR_DONE) { let status = x.status; - if(status >= 200 && status < 300 || status === 304) { + if (status >= 200 && status < 300 || status === 304) { callbacks.success(x.responseText, x); } else { callbacks.error(x.statusText, x); @@ -78,6 +82,8 @@ export function ajax(url, callback, data, options = {}) { } x.open(method, url); + // IE needs timoeut to be set after open - see #1410 + x.timeout = _timeout; if (!useXDomainRequest) { if (options.withCredentials) { diff --git a/src/bidfactory.js b/src/bidfactory.js index 0b43a9b7f4f..74aa5b72a46 100644 --- a/src/bidfactory.js +++ b/src/bidfactory.js @@ -18,7 +18,7 @@ function Bid(statusCode, bidRequest) { var _bidId = bidRequest && bidRequest.bidId || utils.getUniqueIdentifierStr(); var _statusCode = statusCode || 0; - this.bidderCode = ''; + this.bidderCode = (bidRequest && bidRequest.bidder) || ''; this.width = 0; this.height = 0; this.statusMessage = _getStatus(); @@ -41,11 +41,10 @@ function Bid(statusCode, bidRequest) { return _statusCode; }; - //returns the size of the bid creative. Concatenation of width and height by ‘x’. + // returns the size of the bid creative. Concatenation of width and height by ‘x’. this.getSize = function () { return this.width + 'x' + this.height; }; - } // Bid factory function. diff --git a/src/bidmanager.js b/src/bidmanager.js index ea6b41f5203..bfecf9be508 100644 --- a/src/bidmanager.js +++ b/src/bidmanager.js @@ -1,5 +1,8 @@ import { uniques, flatten, adUnitsFilter, getBidderRequest } from './utils'; import {getPriceBucketString} from './cpmBucketManager'; +import {NATIVE_KEYS, nativeBidIsValid} from './native'; +import { store } from './videoCache'; +import { Renderer } from 'src/Renderer'; var CONSTANTS = require('./constants.json'); var AUCTION_END = CONSTANTS.EVENTS.AUCTION_END; @@ -50,9 +53,9 @@ function bidsBackAdUnit(adUnitCode) { .filter(bid => bid.placementCode === adUnitCode)) .reduce(flatten, []) .map(bid => { - return bid.bidder === 'indexExchange' ? - bid.sizes.length : - 1; + return bid.bidder === 'indexExchange' + ? bid.sizes.length + : 1; }).reduce(add, 0); const received = $$PREBID_GLOBAL$$._bidsReceived.filter(bid => bid.adUnitCode === adUnitCode).length; @@ -69,9 +72,9 @@ function bidsBackAll() { .reduce(flatten, []) .filter(adUnitsFilter.bind(this, $$PREBID_GLOBAL$$._adUnitCodes)) .map(bid => { - return bid.bidder === 'indexExchange' ? - bid.sizes.length : - 1; + return bid.bidder === 'indexExchange' + ? bid.sizes.length + : 1; }).reduce((a, b) => a + b, 0); const received = $$PREBID_GLOBAL$$._bidsReceived @@ -88,18 +91,53 @@ exports.bidsBackAll = function () { * This function should be called to by the bidder adapter to register a bid response */ exports.addBidResponse = function (adUnitCode, bid) { - if (!adUnitCode) { - utils.logWarn('No adUnitCode supplied to addBidResponse, response discarded'); - return; + if (isValid()) { + prepareBidForAuction(); + + if (bid.mediaType === 'video') { + tryAddVideoBid(bid); + } else { + doCallbacksIfNeeded(); + addBidToAuction(bid); + } + } + + // Actual method logic is above. Everything below is helper functions. + + // Validate the arguments sent to us by the adapter. If this returns false, the bid should be totally ignored. + function isValid() { + function errorMessage(msg) { + return `Invalid bid from ${bid.bidderCode}. Ignoring bid: ${msg}`; + } + + if (!adUnitCode) { + utils.logWarn('No adUnitCode was supplied to addBidResponse.'); + return false; + } + if (!bid) { + utils.logWarn(`Some adapter tried to add an undefined bid for ${adUnitCode}.`); + return false; + } + if (bid.mediaType === 'native' && !nativeBidIsValid(bid)) { + utils.logError(errorMessage('Native bid missing some required properties.')); + return false; + } + if (bid.mediaType === 'video' && !bid.vastUrl) { + utils.logError(errorMessage(`Video bid does not have required vastUrl property.`)); + return false; + } + return true; } - if (bid) { + // Postprocess the bids so that all the universal properties exist, no matter which bidder they came from. + // This should be called before addBidToAuction(). + function prepareBidForAuction() { + const bidRequest = getBidderRequest(bid.bidderCode, adUnitCode); - const { requestId, start } = getBidderRequest(bid.bidderCode, adUnitCode); Object.assign(bid, { - requestId: requestId, + requestId: bidRequest.requestId, responseTimestamp: timestamp(), - requestTimestamp: start, + requestTimestamp: bidRequest.start, cpm: parseFloat(bid.cpm) || 0, bidder: bid.bidderCode, adUnitCode @@ -114,13 +152,21 @@ exports.addBidResponse = function (adUnitCode, bid) { exports.executeCallback(timedOut); } - //emit the bidAdjustment event before bidResponse, so bid response has the adjusted bid value + // Let listeners know that now is the time to adjust the bid, if they want to. + // + // CAREFUL: Publishers rely on certain bid properties to be available (like cpm), + // but others to not be set yet (like priceStrings). See #1372 and #1389. events.emit(CONSTANTS.EVENTS.BID_ADJUSTMENT, bid); - //emit the bidResponse event - events.emit(CONSTANTS.EVENTS.BID_RESPONSE, bid); + // a publisher-defined renderer can be used to render bids + const adUnitRenderer = + bidRequest.bids && bidRequest.bids[0] && bidRequest.bids[0].renderer; + + if (adUnitRenderer) { + bid.renderer = Renderer.install({ url: adUnitRenderer.url }); + bid.renderer.setRender(adUnitRenderer.render); + } - //append price strings const priceStringsObj = getPriceBucketString(bid.cpm, _customPriceBucket); bid.pbLg = priceStringsObj.low; bid.pbMg = priceStringsObj.med; @@ -129,25 +175,51 @@ exports.addBidResponse = function (adUnitCode, bid) { bid.pbDg = priceStringsObj.dense; bid.pbCg = priceStringsObj.custom; - //if there is any key value pairs to map do here + // if there is any key value pairs to map do here var keyValues = {}; - if (bid.bidderCode && (bid.cpm > 0 || bid.dealId ) ) { + if (bid.bidderCode && (bid.cpm > 0 || bid.dealId)) { keyValues = getKeyValueTargetingPairs(bid.bidderCode, bid); } bid.adserverTargeting = keyValues; - $$PREBID_GLOBAL$$._bidsReceived.push(bid); } - if (bid && bid.adUnitCode && bidsBackAdUnit(bid.adUnitCode)) { - triggerAdUnitCallbacks(bid.adUnitCode); + function doCallbacksIfNeeded() { + if (bid.timeToRespond > $$PREBID_GLOBAL$$.cbTimeout + $$PREBID_GLOBAL$$.timeoutBuffer) { + const timedOut = true; + exports.executeCallback(timedOut); + } } - if (bidsBackAll()) { - exports.executeCallback(); - } else if (_currentTimeoutIndex > 0 && !hasBidsWithPendingTimeouts()) { - // global timeout has already elapsed and all bidders with pending timeouts returned bids - exports.executeCallback(); + // Add a bid to the auction. + function addBidToAuction() { + events.emit(CONSTANTS.EVENTS.BID_RESPONSE, bid); + + $$PREBID_GLOBAL$$._bidsReceived.push(bid); + + if (bid.adUnitCode && bidsBackAdUnit(bid.adUnitCode)) { + triggerAdUnitCallbacks(bid.adUnitCode); + } + + if (bidsBackAll()) { + exports.executeCallback(); + } else if (_currentTimeoutIndex > 0 && !hasBidsWithPendingTimeouts()) { + // global timeout has already elapsed and all bidders with pending timeouts returned bids + exports.executeCallback(); + } + } + + // Video bids may fail if the cache is down, or there's trouble on the network. + function tryAddVideoBid(bid) { + store([bid], function(error, cacheIds) { + if (error) { + utils.logWarn(`Failed to save to the video cache: ${error}. Video bid must be discarded.`); + } else { + bid.videoCacheKey = cacheIds[0].uuid; + addBidToAuction(bid); + } + doCallbacksIfNeeded(); + }); } }; @@ -155,27 +227,36 @@ function getKeyValueTargetingPairs(bidderCode, custBidObj) { var keyValues = {}; var bidder_settings = $$PREBID_GLOBAL$$.bidderSettings; - //1) set the keys from "standard" setting or from prebid defaults + // 1) set the keys from "standard" setting or from prebid defaults if (custBidObj && bidder_settings) { - //initialize default if not set + // initialize default if not set const standardSettings = getStandardBidderSettings(); setKeys(keyValues, standardSettings, custBidObj); } - //2) set keys from specific bidder setting override if they exist + // 2) set keys from specific bidder setting override if they exist if (bidderCode && custBidObj && bidder_settings && bidder_settings[bidderCode] && bidder_settings[bidderCode][CONSTANTS.JSON_MAPPING.ADSERVER_TARGETING]) { setKeys(keyValues, bidder_settings[bidderCode], custBidObj); custBidObj.alwaysUseBid = bidder_settings[bidderCode].alwaysUseBid; custBidObj.sendStandardTargeting = bidder_settings[bidderCode].sendStandardTargeting; } - //2) set keys from standard setting. NOTE: this API doesn't seem to be in use by any Adapter + // 2) set keys from standard setting. NOTE: this API doesn't seem to be in use by any Adapter else if (defaultBidderSettingsMap[bidderCode]) { setKeys(keyValues, defaultBidderSettingsMap[bidderCode], custBidObj); custBidObj.alwaysUseBid = defaultBidderSettingsMap[bidderCode].alwaysUseBid; custBidObj.sendStandardTargeting = defaultBidderSettingsMap[bidderCode].sendStandardTargeting; } + // set native key value targeting + if (custBidObj.native) { + Object.keys(custBidObj.native).forEach(asset => { + const key = NATIVE_KEYS[asset]; + const value = custBidObj.native[asset]; + if (key) { keyValues[key] = value; } + }); + } + return keyValues; } @@ -204,8 +285,8 @@ function setKeys(keyValues, bidderSettings, custBidObj) { } if ( - (typeof bidderSettings.suppressEmptyKeys !== "undefined" && bidderSettings.suppressEmptyKeys === true || - key === "hb_deal") && // hb_deal is suppressed automatically if not set + (typeof bidderSettings.suppressEmptyKeys !== 'undefined' && bidderSettings.suppressEmptyKeys === true || + key === 'hb_deal') && // hb_deal is suppressed automatically if not set ( utils.isEmptyStr(value) || value === null || @@ -216,7 +297,6 @@ function setKeys(keyValues, bidderSettings, custBidObj) { } else { keyValues[key] = value; } - }); return keyValues; @@ -300,16 +380,14 @@ exports.executeCallback = function (timedOut) { } } - //execute one time callback + // execute one time callback if (externalCallbacks.oneTime) { events.emit(AUCTION_END); try { processCallbacks([externalCallbacks.oneTime]); - } - catch(e){ + } catch (e) { utils.logError('Error executing bidsBackHandler', null, e); - } - finally { + } finally { externalCallbacks.oneTime = null; exports.setTimeouts([]); $$PREBID_GLOBAL$$.clearAuction(); @@ -322,7 +400,7 @@ exports.externalCallbackReset = function () { }; function triggerAdUnitCallbacks(adUnitCode) { - //todo : get bid responses and send in args + // todo : get bid responses and send in args var singleAdUnitCode = [adUnitCode]; processCallbacks(externalCallbacks.byAdUnit, singleAdUnitCode); } @@ -332,8 +410,8 @@ function processCallbacks(callbackQueue, singleAdUnitCode) { callbackQueue.forEach(callback => { const adUnitCodes = singleAdUnitCode || $$PREBID_GLOBAL$$._adUnitCodes; const bids = [$$PREBID_GLOBAL$$._bidsReceived - .filter(adUnitsFilter.bind(this, adUnitCodes)) - .reduce(groupByPlacement, {})]; + .filter(adUnitsFilter.bind(this, adUnitCodes)) + .reduce(groupByPlacement, {})]; callback.apply($$PREBID_GLOBAL$$, bids); }); @@ -347,8 +425,7 @@ function processCallbacks(callbackQueue, singleAdUnitCode) { * @returns {*} as { [adUnitCode]: { bids: [Bid, Bid, Bid] } } */ function groupByPlacement(bidsByPlacement, bid) { - if (!bidsByPlacement[bid.adUnitCode]) - bidsByPlacement[bid.adUnitCode] = { bids: [] }; + if (!bidsByPlacement[bid.adUnitCode]) { bidsByPlacement[bid.adUnitCode] = { bids: [] }; } bidsByPlacement[bid.adUnitCode].bids.push(bid); @@ -374,7 +451,7 @@ exports.addCallback = function (id, callback, cbEvent) { } }; -//register event for bid adjustment +// register event for bid adjustment events.on(CONSTANTS.EVENTS.BID_ADJUSTMENT, function (bid) { adjustBids(bid); }); @@ -386,8 +463,7 @@ function adjustBids(bid) { if (typeof $$PREBID_GLOBAL$$.bidderSettings[code].bidCpmAdjustment === objectType_function) { try { bidPriceAdjusted = $$PREBID_GLOBAL$$.bidderSettings[code].bidCpmAdjustment.call(null, bid.cpm, Object.assign({}, bid)); - } - catch (e) { + } catch (e) { utils.logError('Error during bid adjustment', 'bidmanager.js', e); } } diff --git a/src/constants.json b/src/constants.json index 4cf0aac447d..4abb08b46d9 100644 --- a/src/constants.json +++ b/src/constants.json @@ -61,6 +61,9 @@ "hb_deal" ], "S2S" : { - "DEFAULT_ENDPOINT" : "https://prebid.adnxs.com/pbs/v1/auction" + "DEFAULT_ENDPOINT" : "https://prebid.adnxs.com/pbs/v1/auction", + "SRC" : "s2s", + "ADAPTER" : "prebidServer", + "SYNC_ENDPOINT" : "https://prebid.adnxs.com/pbs/v1/cookie_sync" } } diff --git a/src/cookie.js b/src/cookie.js index 8e823b1acd9..e552232b132 100644 --- a/src/cookie.js +++ b/src/cookie.js @@ -1,18 +1,19 @@ const cookie = exports; -import * as utils from 'utils'; +import * as utils from './utils'; +import adLoader from './adloader'; const queue = []; function fireSyncs() { queue.forEach(obj => { utils.logMessage(`Invoking cookie sync for bidder: ${obj.bidder}`); - if(obj.type === 'iframe') { + if (obj.type === 'iframe') { utils.insertCookieSyncIframe(obj.url, false); } else { utils.insertPixel(obj.url); } }); - //empty queue. + // empty queue. queue.length = 0; } @@ -30,7 +31,7 @@ cookie.queueSync = function ({bidder, url, type}) { * @param {number} timeout time in ms to delay in sending */ cookie.syncCookies = function(timeout) { - if(timeout) { + if (timeout) { setTimeout(fireSyncs, timeout); } else { @@ -38,48 +39,9 @@ cookie.syncCookies = function(timeout) { } }; -cookie.persist = function(url, msgHtml) { - if(!utils.isSafariBrowser()){ +cookie.cookieSet = function(cookieSetUrl) { + if (!utils.isSafariBrowser()) { return; } - linkOverride(url); - displayFooter(msgHtml); + adLoader.loadScript(cookieSetUrl, null, true); }; - -function linkOverride(url) { - for (var i = 0; i < document.links.length; i++){ - var link = document.links[i]; - link.href = url + encodeURIComponent(link.href); - } - } - -function displayFooter(msgHtml) { - // https://developer.mozilla.org/en-US/docs/Web/API/Document/cookie#Example_3_Do_something_only_once - if (document.cookie.replace(/(?:(?:^|.*;\s*)pbsCookiePersistFooter\s*\=\s*([^;]*).*$)|^.*$/, '$1') !== 'true') { - document.body.appendChild(createFooter(msgHtml)); - document.cookie = 'pbsCookiePersistFooter=true; expires=Fri, 31 Dec 9999 23:59:59 GMT'; - } -} - -function createFooter(msgHtml) { - const footer = document.createElement('div'); - footer.style.background = '#D3D3D3'; - footer.style.color = '#555'; - footer.style.boxShadow = '0 -1px 2px rgba(0, 0, 0, 0.2)'; - footer.style.fontFamily = 'sans-serif'; - footer.style.lineHeight = '1.5'; - footer.style.position = 'fixed'; - footer.style.bottom = '0'; - footer.style.left = '0'; - footer.style.right = '0'; - footer.style.width = '100%'; - footer.style.padding = '1em 0'; - footer.style.zindex = '1000'; - - const footerText = document.createElement('p'); - footerText.style.margin = '0 2em'; - footerText.innerHTML = msgHtml; - footer.appendChild(footerText); - - return footer; -} diff --git a/src/cpmBucketManager.js b/src/cpmBucketManager.js index 5630204ac28..c135a644dc1 100644 --- a/src/cpmBucketManager.js +++ b/src/cpmBucketManager.js @@ -22,37 +22,37 @@ const _hgPriceConfig = { }; const _densePriceConfig = { 'buckets': [{ - 'min': 0, - 'max': 3, - 'increment': 0.01 - }, - { - 'min': 3, - 'max': 8, - 'increment': 0.05 - }, - { - 'min': 8, - 'max': 20, - 'increment': 0.5 - }] + 'min': 0, + 'max': 3, + 'increment': 0.01 + }, + { + 'min': 3, + 'max': 8, + 'increment': 0.05 + }, + { + 'min': 8, + 'max': 20, + 'increment': 0.5 + }] }; const _autoPriceConfig = { 'buckets': [{ - 'min': 0, - 'max': 5, - 'increment': 0.05 - }, - { - 'min': 5, - 'max': 10, - 'increment': 0.1 - }, - { - 'min': 10, - 'max': 20, - 'increment': 0.5 - }] + 'min': 0, + 'max': 5, + 'increment': 0.05 + }, + { + 'min': 5, + 'max': 10, + 'increment': 0.1 + }, + { + 'min': 10, + 'max': 20, + 'increment': 0.5 + }] }; function getPriceBucketString(cpm, customConfig) { @@ -68,7 +68,7 @@ function getPriceBucketString(cpm, customConfig) { high: (cpmFloat === '') ? '' : getCpmStringValue(cpm, _hgPriceConfig), auto: (cpmFloat === '') ? '' : getCpmStringValue(cpm, _autoPriceConfig), dense: (cpmFloat === '') ? '' : getCpmStringValue(cpm, _densePriceConfig), - custom: (cpmFloat === '') ? '' : getCpmStringValue(cpm, customConfig) + custom: (cpmFloat === '') ? '' : getCpmStringValue(cpm, customConfig) }; } @@ -77,7 +77,7 @@ function getCpmStringValue(cpm, config) { if (!isValidePriceConfig(config)) { return cpmStr; } - const cap = config.buckets.reduce((prev,curr) => { + const cap = config.buckets.reduce((prev, curr) => { if (prev.max > curr.max) { return prev; } @@ -105,7 +105,7 @@ function isValidePriceConfig(config) { } let isValid = true; config.buckets.forEach(bucket => { - if(typeof bucket.min === 'undefined' || !bucket.max || !bucket.increment) { + if (typeof bucket.min === 'undefined' || !bucket.max || !bucket.increment) { isValid = false; } }); diff --git a/src/events.js b/src/events.js index 2b52de1c38f..abef24d6ea3 100644 --- a/src/events.js +++ b/src/events.js @@ -6,19 +6,18 @@ var CONSTANTS = require('./constants'); var slice = Array.prototype.slice; var push = Array.prototype.push; -//define entire events -//var allEvents = ['bidRequested','bidResponse','bidWon','bidTimeout']; +// define entire events +// var allEvents = ['bidRequested','bidResponse','bidWon','bidTimeout']; var allEvents = utils._map(CONSTANTS.EVENTS, function (v) { return v; }); var idPaths = CONSTANTS.EVENT_ID_PATHS; -//keep a record of all events fired +// keep a record of all events fired var eventsFired = []; module.exports = (function () { - var _handlers = {}; var _public = {}; @@ -41,7 +40,7 @@ module.exports = (function () { var callbacks = []; - //record the event: + // record the event: eventsFired.push({ eventType: eventString, args: eventPayload, @@ -66,8 +65,7 @@ module.exports = (function () { if (!fn) return; try { fn.apply(null, args); - } - catch (e) { + } catch (e) { utils.logError('Error executing handler:', 'events.js', e); } }); @@ -78,8 +76,7 @@ module.exports = (function () { } _public.on = function (eventString, handler, id) { - - //check whether available event or not + // check whether available event or not if (_checkAvailableEvent(eventString)) { var event = _handlers[eventString] || { que: [] }; diff --git a/src/native.js b/src/native.js new file mode 100644 index 00000000000..28016354ba8 --- /dev/null +++ b/src/native.js @@ -0,0 +1,96 @@ +import { getBidRequest, logError, insertPixel } from './utils'; + +export const nativeAdapters = []; + +export const NATIVE_KEYS = { + title: 'hb_native_title', + body: 'hb_native_body', + sponsoredBy: 'hb_native_brand', + image: 'hb_native_image', + icon: 'hb_native_icon', + clickUrl: 'hb_native_linkurl', +}; + +export const NATIVE_TARGETING_KEYS = Object.keys(NATIVE_KEYS).map( + key => NATIVE_KEYS[key] +); + +const IMAGE = { + image: {required: true}, + title: {required: true}, + sponsoredBy: {required: true}, + clickUrl: {required: true}, + body: {required: false}, + icon: {required: false}, +}; + +const SUPPORTED_TYPES = { + image: IMAGE +}; + +/** + * Recieves nativeParams from an adUnit. If the params were not of type 'type', + * passes them on directly. If they were of type 'type', translate + * them into the predefined specific asset requests for that type of native ad. + */ +export function processNativeAdUnitParams(params) { + if (params && params.type && typeIsSupported(params.type)) { + return SUPPORTED_TYPES[params.type]; + } + + return params; +} + +/** + * Check if the native type specified in the adUnit is supported by Prebid. + */ +function typeIsSupported(type) { + if (!(type && Object.keys(SUPPORTED_TYPES).includes(type))) { + logError(`${type} nativeParam is not supported`); + return false; + } + + return true; +} + +/** + * Helper functions for working with native-enabled adUnits + * TODO: abstract this and the video helper functions into general + * adunit validation helper functions + */ +export const nativeAdUnit = adUnit => adUnit.mediaType === 'native'; +export const nativeBidder = bid => nativeAdapters.includes(bid.bidder); +export const hasNonNativeBidder = adUnit => + adUnit.bids.filter(bid => !nativeBidder(bid)).length; + +/* + * Validate that the native assets on this bid contain all assets that were + * marked as required in the adUnit configuration. + */ +export function nativeBidIsValid(bid) { + const bidRequest = getBidRequest(bid.adId); + if (!bidRequest) { return false; } + + const requestedAssets = bidRequest.nativeParams; + if (!requestedAssets) { return true; } + + const requiredAssets = Object.keys(requestedAssets).filter( + key => requestedAssets[key].required + ); + const returnedAssets = Object.keys(bid.native).filter(key => bid.native[key]); + + return requiredAssets.every(asset => returnedAssets.includes(asset)); +} + +/* + * Native responses may have impression trackers. This retrieves the + * impression tracker urls for the given ad object and fires them. + */ +export function fireNativeImpressions(adObject) { + const impressionTrackers = adObject.native && + adObject.native.impressionTrackers; + + (impressionTrackers || []).forEach(tracker => { + insertPixel(tracker); + }); +} diff --git a/src/polyfill.js b/src/polyfill.js index 586e0d6e918..1c8913824ae 100644 --- a/src/polyfill.js +++ b/src/polyfill.js @@ -1,8 +1,8 @@ /** @module polyfill Misc polyfills */ -/*jshint -W121 */ require('core-js/fn/array/find'); +require('core-js/fn/array/find-index'); require('core-js/fn/array/includes'); require('core-js/fn/object/assign'); diff --git a/src/prebid.js b/src/prebid.js index 5ec347b8327..680c4056420 100644 --- a/src/prebid.js +++ b/src/prebid.js @@ -1,14 +1,16 @@ /** @module $$PREBID_GLOBAL$$ */ import { getGlobal } from './prebidGlobal'; -import {flatten, uniques, isGptPubadsDefined, adUnitsFilter } from './utils'; +import { flatten, uniques, isGptPubadsDefined, adUnitsFilter } from './utils'; import { videoAdUnit, hasNonVideoBidder } from './video'; -import 'polyfill'; -import {parse as parseURL, format as formatURL} from './url'; -import {isValidePriceConfig} from './cpmBucketManager'; -import {listenMessagesFromCreative} from './secure-creatives'; -import { syncCookies } from 'src/cookie.js'; +import { nativeAdUnit, nativeBidder, hasNonNativeBidder } from './native'; +import './polyfill'; +import { parse as parseURL, format as formatURL } from './url'; +import { isValidePriceConfig } from './cpmBucketManager'; +import { listenMessagesFromCreative } from './secureCreatives'; +import { syncCookies } from './cookie'; import { loadScript } from './adloader'; +import { setAjaxTimeout } from './ajax'; var $$PREBID_GLOBAL$$ = getGlobal(); @@ -48,7 +50,7 @@ $$PREBID_GLOBAL$$._sendAllBids = false; $$PREBID_GLOBAL$$.bidderSettings = $$PREBID_GLOBAL$$.bidderSettings || {}; -//default timeout for all bids +// default timeout for all bids $$PREBID_GLOBAL$$.bidderTimeout = $$PREBID_GLOBAL$$.bidderTimeout || 3000; // current timeout set in `requestBids` or to default `bidderTimeout` @@ -62,51 +64,19 @@ $$PREBID_GLOBAL$$.logging = $$PREBID_GLOBAL$$.logging || false; // domain where prebid is running for cross domain iframe communication $$PREBID_GLOBAL$$.publisherDomain = $$PREBID_GLOBAL$$.publisherDomain || window.location.origin; -//let the world know we are loaded +// let the world know we are loaded $$PREBID_GLOBAL$$.libLoaded = true; -//version auto generated from build +// version auto generated from build $$PREBID_GLOBAL$$.version = 'v$prebid.version$'; utils.logInfo('Prebid.js v$prebid.version$ loaded'); -//create adUnit array +// create adUnit array $$PREBID_GLOBAL$$.adUnits = $$PREBID_GLOBAL$$.adUnits || []; -//delay to request cookie sync to stay out of critical path +// delay to request cookie sync to stay out of critical path $$PREBID_GLOBAL$$.cookieSyncDelay = $$PREBID_GLOBAL$$.cookieSyncDelay || 100; - -/** - * Command queue that functions will execute once prebid.js is loaded - * @param {function} cmd Anonymous function to execute - * @alias module:$$PREBID_GLOBAL$$.que.push - */ -$$PREBID_GLOBAL$$.que.push = function (cmd) { - if (typeof cmd === objectType_function) { - try { - cmd.call(); - } catch (e) { - utils.logError('Error processing command :' + e.message); - } - } else { - utils.logError('Commands written into $$PREBID_GLOBAL$$.que.push must wrapped in a function'); - } -}; - -function processQue() { - for (var i = 0; i < $$PREBID_GLOBAL$$.que.length; i++) { - if (typeof $$PREBID_GLOBAL$$.que[i].called === objectType_undefined) { - try { - $$PREBID_GLOBAL$$.que[i].call(); - $$PREBID_GLOBAL$$.que[i].called = true; - } - catch (e) { - utils.logError('Error processing command :', 'prebid.js', e); - } - } - } -} - function checkDefinedPlacement(id) { var placementCodes = $$PREBID_GLOBAL$$._bidsRequested.map(bidSet => bidSet.bids.map(bid => bid.placementCode)) .reduce(flatten) @@ -139,11 +109,11 @@ function setRenderSize(doc, width, height) { } } -////////////////////////////////// +/// /////////////////////////////// // // // Start Public APIs // // // -////////////////////////////////// +/// /////////////////////////////// /** * This function returns the query string targeting parameters available at this moment for a given ad unit. Note that some bidder's response may not have been received if you call this function too quickly after the requests are sent. @@ -239,36 +209,41 @@ $$PREBID_GLOBAL$$.getBidResponsesForAdUnitCode = function (adUnitCode) { }; /** - * Set query string targeting on all GPT ad units. + * Set query string targeting on one or more GPT ad units. + * @param {(string|string[])} adUnit a single `adUnit.code` or multiple. * @alias module:$$PREBID_GLOBAL$$.setTargetingForGPTAsync */ -$$PREBID_GLOBAL$$.setTargetingForGPTAsync = function () { +$$PREBID_GLOBAL$$.setTargetingForGPTAsync = function (adUnit) { utils.logInfo('Invoking $$PREBID_GLOBAL$$.setTargetingForGPTAsync', arguments); if (!isGptPubadsDefined()) { utils.logError('window.googletag is not defined on the page'); return; } - //first reset any old targeting - targeting.resetPresetTargeting(); + // get our ad unit codes + var targetingSet = targeting.getAllTargeting(adUnit); + + // first reset any old targeting + targeting.resetPresetTargeting(adUnit); + + // now set new targeting keys + targeting.setTargeting(targetingSet); - //now set new targeting keys - targeting.setTargeting(targeting.getAllTargeting()); - //emit event + // emit event events.emit(SET_TARGETING); }; $$PREBID_GLOBAL$$.setTargetingForAst = function() { utils.logInfo('Invoking $$PREBID_GLOBAL$$.setTargetingForAn', arguments); - if(!targeting.isApntagDefined()) { + if (!targeting.isApntagDefined()) { utils.logError('window.apntag is not defined on the page'); return; } targeting.setTargetingForAst(); - //emit event + // emit event events.emit(SET_TARGETING); }; @@ -294,16 +269,16 @@ $$PREBID_GLOBAL$$.renderAd = function (doc, id) { utils.logMessage('Calling renderAd with adId :' + id); if (doc && id) { try { - //lookup ad by ad Id + // lookup ad by ad Id const bid = $$PREBID_GLOBAL$$._bidsReceived.find(bid => bid.adId === id); if (bid) { - //replace macros according to openRTB with price paid = bid.cpm + // replace macros according to openRTB with price paid = bid.cpm bid.ad = utils.replaceAuctionPrice(bid.ad, bid.cpm); bid.url = utils.replaceAuctionPrice(bid.url, bid.cpm); - //save winning bids + // save winning bids $$PREBID_GLOBAL$$._winningBids.push(bid); - //emit 'bid won' event here + // emit 'bid won' event here events.emit(BID_WON, bid); const { height, width, ad, mediaType, adUrl: url, renderer } = bid; @@ -317,24 +292,27 @@ $$PREBID_GLOBAL$$.renderAd = function (doc, id) { doc.close(); setRenderSize(doc, width, height); } else if (url) { - doc.write(``); - doc.close(); + const iframe = utils.createInvisibleIframe(); + iframe.height = height; + iframe.width = width; + iframe.style.display = 'inline'; + iframe.style.overflow = 'hidden'; + iframe.src = url; + + utils.insertElement(iframe, doc, 'body'); setRenderSize(doc, width, height); } else { utils.logError('Error trying to write ad. No ad for bid response id: ' + id); } - } else { utils.logError('Error trying to write ad. Cannot find ad by given id : ' + id); } - } catch (e) { utils.logError('Error trying to write ad Id :' + id + ' to the page:' + e.message); } } else { utils.logError('Error trying to write ad Id :' + id + ' to the page. Missing document or adId'); } - }; /** @@ -389,10 +367,21 @@ $$PREBID_GLOBAL$$.requestBids = function ({ bidsBackHandler, timeout, adUnits, a invalidVideoAdUnits.forEach(adUnit => { utils.logError(`adUnit ${adUnit.code} has 'mediaType' set to 'video' but contains a bidder that doesn't support video. No Prebid demand requests will be triggered for this adUnit.`); for (let i = 0; i < adUnits.length; i++) { - if (adUnits[i].code === adUnit.code) {adUnits.splice(i, 1);} + if (adUnits[i].code === adUnit.code) { adUnits.splice(i, 1); } } }); + // for native-enabled adUnits, only request bids for bidders that support native + adUnits.filter(nativeAdUnit).filter(hasNonNativeBidder).forEach(adUnit => { + const nonNativeBidders = adUnit.bids + .filter(bid => !nativeBidder(bid)) + .map(bid => bid.bidder) + .join(', '); + + utils.logError(`adUnit ${adUnit.code} has 'mediaType' set to 'native' but contains non-native bidder(s) ${nonNativeBidders}. No Prebid demand requests will be triggered for those bidders.`); + adUnit.bids = adUnit.bids.filter(nativeBidder); + }); + if (auctionRunning) { bidRequestQueue.push(() => { $$PREBID_GLOBAL$$.requestBids({ bidsBackHandler, timeout: cbTimeout, adUnits, adUnitCodes }); @@ -421,6 +410,8 @@ $$PREBID_GLOBAL$$.requestBids = function ({ bidsBackHandler, timeout, adUnits, a bidmanager.addOneTimeCallback(bidsBackHandler, false); } + setAjaxTimeout(cbTimeout); + var timeouts = [cbTimeout]; var bidderSettings = $$PREBID_GLOBAL$$.bidderSettings; @@ -436,11 +427,11 @@ $$PREBID_GLOBAL$$.requestBids = function ({ bidsBackHandler, timeout, adUnits, a timeouts.sort((a, b) => a - b); } - //set timeout(s) for all bids + // set timeout(s) for all bids bidmanager.setTimeouts(timeouts); adaptermanager.callBids({ adUnits, adUnitCodes, cbTimeout }); - if($$PREBID_GLOBAL$$._bidsRequested.length === 0) { + if ($$PREBID_GLOBAL$$._bidsRequested.length === 0) { bidmanager.executeCallback(); } }; @@ -448,7 +439,7 @@ $$PREBID_GLOBAL$$.requestBids = function ({ bidsBackHandler, timeout, adUnits, a /** * * Add adunit(s) - * @param {Array|String} adUnitArr Array of adUnits or single adUnit Object. + * @param {Array|Object} adUnitArr Array of adUnits or single adUnit Object. * @alias module:$$PREBID_GLOBAL$$.addAdUnits */ $$PREBID_GLOBAL$$.addAdUnits = function (adUnitArr) { @@ -536,7 +527,7 @@ $$PREBID_GLOBAL$$.addCallback = function (eventStr, func) { * @returns {String} id for callback */ $$PREBID_GLOBAL$$.removeCallback = function (/* cbId */) { - //todo + // todo return null; }; @@ -655,11 +646,11 @@ $$PREBID_GLOBAL$$.setPriceGranularity = function (granularity) { utils.logError('Prebid Error: no value passed to `setPriceGranularity()`'); return; } - if(typeof granularity === 'string') { + if (typeof granularity === 'string') { bidmanager.setPriceGranularity(granularity); } - else if(typeof granularity === 'object') { - if(!isValidePriceConfig(granularity)){ + else if (typeof granularity === 'object') { + if (!isValidePriceConfig(granularity)) { utils.logError('Invalid custom price value passed to `setPriceGranularity()`'); return; } @@ -681,20 +672,25 @@ $$PREBID_GLOBAL$$.getAllWinningBids = function () { * Build master video tag from publishers adserver tag * @param {string} adserverTag default url * @param {object} options options for video tag + * + * @deprecated Include the dfpVideoSupport module in your build, and use the + * $$PREBID_GLOBAL$$.adserver.buildVideoAdUrl (if DFP is your only Ad Server) or + * $$PREBID_GLOBAL$$.adservers.dfp.buildVideoAdUrl (if you use other Ad Servers too) + * function instead. This function will be removed in Prebid 1.0. */ $$PREBID_GLOBAL$$.buildMasterVideoTagFromAdserverTag = function (adserverTag, options) { utils.logInfo('Invoking $$PREBID_GLOBAL$$.buildMasterVideoTagFromAdserverTag', arguments); var urlComponents = parseURL(adserverTag); - //return original adserverTag if no bids received - if($$PREBID_GLOBAL$$._bidsReceived.length === 0) { + // return original adserverTag if no bids received + if ($$PREBID_GLOBAL$$._bidsReceived.length === 0) { return adserverTag; } var masterTag = ''; - if(options.adserver.toLowerCase() === 'dfp') { + if (options.adserver.toLowerCase() === 'dfp') { var dfpAdserverObj = adserver.dfpAdserver(options, urlComponents); - if(!dfpAdserverObj.verifyAdserverTag()) { + if (!dfpAdserverObj.verifyAdserverTag()) { utils.logError('Invalid adserverTag, required google params are missing in query string'); } dfpAdserverObj.appendQueryParams(); @@ -730,10 +726,17 @@ $$PREBID_GLOBAL$$.getHighestCpmBids = function (adUnitCode) { /** * Set config for server to server header bidding - * @param {object} options - config object for s2s + * @typedef {Object} options - required + * @property {boolean} enabled enables S2S bidding + * @property {string[]} bidders bidders to request S2S + * === optional params below === + * @property {string} [endpoint] endpoint to contact + * @property {number} [timeout] timeout for S2S bidders - should be lower than `pbjs.requestBids({timeout})` + * @property {string} [adapter] adapter code to use for S2S + * @property {string} [syncEndpoint] endpoint URL for syncing cookies + * @property {boolean} [cookieSet] enables cookieSet functionality */ $$PREBID_GLOBAL$$.setS2SConfig = function(options) { - if (!utils.contains(Object.keys(options), 'accountId')) { utils.logError('accountId missing in Server to Server config'); return; @@ -745,15 +748,68 @@ $$PREBID_GLOBAL$$.setS2SConfig = function(options) { } const config = Object.assign({ - enabled : false, - endpoint : CONSTANTS.S2S.DEFAULT_ENDPOINT, - timeout : 1000, - maxBids : 1, - adapter : 'prebidServer' + enabled: false, + endpoint: CONSTANTS.S2S.DEFAULT_ENDPOINT, + timeout: 1000, + maxBids: 1, + adapter: CONSTANTS.S2S.ADAPTER, + syncEndpoint: CONSTANTS.S2S.SYNC_ENDPOINT, + cookieSet: true, + bidders: [] }, options); adaptermanager.setS2SConfig(config); }; - $$PREBID_GLOBAL$$.que.push(() => listenMessagesFromCreative()); -processQue(); + +/** + * This queue lets users load Prebid asynchronously, but run functions the same way regardless of whether it gets loaded + * before or after their script executes. For example, given the code: + * + * + * + * + * If the page's script runs before prebid loads, then their function gets added to the queue, and executed + * by prebid once it's done loading. If it runs after prebid loads, then this monkey-patch causes their + * function to execute immediately. + * + * @param {function} cmd A function which takes no arguments. This is guaranteed to run exactly once, and only after + * the Prebid script has been fully loaded. + * @alias module:$$PREBID_GLOBAL$$.cmd.push + */ +$$PREBID_GLOBAL$$.cmd.push = function(cmd) { + if (typeof cmd === objectType_function) { + try { + cmd.call(); + } catch (e) { + utils.logError('Error processing command :' + e.message); + } + } else { + utils.logError('Commands written into $$PREBID_GLOBAL$$.cmd.push must be wrapped in a function'); + } +}; + +$$PREBID_GLOBAL$$.que.push = $$PREBID_GLOBAL$$.cmd.push; + +function processQueue(queue) { + queue.forEach(function(cmd) { + if (typeof cmd.called === objectType_undefined) { + try { + cmd.call(); + cmd.called = true; + } + catch (e) { + utils.logError('Error processing command :', 'prebid.js', e); + } + } + }); +} + +$$PREBID_GLOBAL$$.processQueue = function() { + processQueue($$PREBID_GLOBAL$$.que); + processQueue($$PREBID_GLOBAL$$.cmd); +}; diff --git a/src/prebidGlobal.js b/src/prebidGlobal.js index 0ba9edcab1a..ec685236468 100644 --- a/src/prebidGlobal.js +++ b/src/prebidGlobal.js @@ -1,6 +1,7 @@ // if $$PREBID_GLOBAL$$ already exists in global document scope, use it, if not, create the object // global defination should happen BEFORE imports to avoid global undefined errors. window.$$PREBID_GLOBAL$$ = (window.$$PREBID_GLOBAL$$ || {}); +window.$$PREBID_GLOBAL$$.cmd = window.$$PREBID_GLOBAL$$.cmd || []; window.$$PREBID_GLOBAL$$.que = window.$$PREBID_GLOBAL$$.que || []; export function getGlobal() { diff --git a/src/secure-creatives.js b/src/secureCreatives.js similarity index 75% rename from src/secure-creatives.js rename to src/secureCreatives.js index e559928bb79..2402ba755f4 100644 --- a/src/secure-creatives.js +++ b/src/secureCreatives.js @@ -4,11 +4,11 @@ */ import events from './events'; +import { fireNativeImpressions } from './native'; import { EVENTS } from './constants'; const BID_WON = EVENTS.BID_WON; - export function listenMessagesFromCreative() { addEventListener('message', receiveMessage, false); } @@ -29,6 +29,21 @@ function receiveMessage(ev) { if (data.message === 'Prebid Request') { sendAdToCreative(adObject, data.adServerDomain, ev.source); + + // save winning bids + $$PREBID_GLOBAL$$._winningBids.push(adObject); + + events.emit(BID_WON, adObject); + } + + // handle this script from native template in an ad server + // window.parent.postMessage(JSON.stringify({ + // message: 'Prebid Native', + // adId: '%%PATTERN:hb_adid%%' + // }), '*'); + if (data.message === 'Prebid Native') { + fireNativeImpressions(adObject); + $$PREBID_GLOBAL$$._winningBids.push(adObject); events.emit(BID_WON, adObject); } } diff --git a/src/sizeMapping.js b/src/sizeMapping.js index 90ce5b68851..53c2c63b542 100644 --- a/src/sizeMapping.js +++ b/src/sizeMapping.js @@ -5,37 +5,36 @@ import * as utils from './utils'; let _win; function mapSizes(adUnit) { - if(!isSizeMappingValid(adUnit.sizeMapping)){ + if (!isSizeMappingValid(adUnit.sizeMapping)) { return adUnit.sizes; } const width = getScreenWidth(); - if(!width) { - //size not detected - get largest value set for desktop + if (!width) { + // size not detected - get largest value set for desktop const mapping = adUnit.sizeMapping.reduce((prev, curr) => { return prev.minWidth < curr.minWidth ? curr : prev; }); - if(mapping.sizes && mapping.sizes.length) { + if (mapping.sizes && mapping.sizes.length) { return mapping.sizes; } return adUnit.sizes; } let sizes = ''; - const mapping = adUnit.sizeMapping.find(sizeMapping =>{ + const mapping = adUnit.sizeMapping.find(sizeMapping => { return width > sizeMapping.minWidth; }); - if(mapping && mapping.sizes && mapping.sizes.length){ + if (mapping && mapping.sizes && mapping.sizes.length) { sizes = mapping.sizes; utils.logMessage(`AdUnit : ${adUnit.code} resized based on device width to : ${sizes}`); } - else{ + else { utils.logMessage(`AdUnit : ${adUnit.code} not mapped to any sizes for device width. This request will be suppressed.`); } return sizes; - } function isSizeMappingValid(sizeMapping) { - if(utils.isArray(sizeMapping) && sizeMapping.length > 0){ + if (utils.isArray(sizeMapping) && sizeMapping.length > 0) { return true; } utils.logInfo('No size mapping defined'); diff --git a/src/targeting.js b/src/targeting.js index 63ac2937a77..1dcbd583089 100644 --- a/src/targeting.js +++ b/src/targeting.js @@ -1,17 +1,20 @@ import { uniques, isGptPubadsDefined, getHighestCpm, adUnitsFilter } from './utils'; -const bidmanager = require('./bidmanager.js'); -const utils = require('./utils.js'); -var CONSTANTS = require('./constants.json'); +import { NATIVE_TARGETING_KEYS } from './native'; +const bidmanager = require('./bidmanager'); +const utils = require('./utils'); +var CONSTANTS = require('./constants'); var targeting = exports; var pbTargetingKeys = []; -targeting.resetPresetTargeting = function() { +targeting.resetPresetTargeting = function(adUnitCode) { if (isGptPubadsDefined()) { + const adUnitCodes = getAdUnitCodes(adUnitCode); + const adUnits = $$PREBID_GLOBAL$$.adUnits.filter(adUnit => adUnitCodes.includes(adUnit.code)); window.googletag.pubads().getSlots().forEach(slot => { - pbTargetingKeys.forEach(function(key){ + pbTargetingKeys.forEach(function(key) { // reset only registered adunits - $$PREBID_GLOBAL$$.adUnits.find(function(unit) { + adUnits.forEach(function(unit) { if (unit.code === slot.getAdUnitPath() || unit.code === slot.getSlotElementId()) { slot.setTargeting(key, null); @@ -23,15 +26,15 @@ targeting.resetPresetTargeting = function() { }; targeting.getAllTargeting = function(adUnitCode) { - const adUnitCodes = adUnitCode && adUnitCode.length ? [adUnitCode] : $$PREBID_GLOBAL$$._adUnitCodes; + const adUnitCodes = getAdUnitCodes(adUnitCode); // Get targeting for the winning bid. Add targeting for any bids that have // `alwaysUseBid=true`. If sending all bids is enabled, add targeting for losing bids. var targeting = getWinningBidTargeting(adUnitCodes) - .concat(getAlwaysUseBidTargeting(adUnitCodes)) - .concat($$PREBID_GLOBAL$$._sendAllBids ? getBidLandscapeTargeting(adUnitCodes) : []); + .concat(getAlwaysUseBidTargeting(adUnitCodes)) + .concat($$PREBID_GLOBAL$$._sendAllBids ? getBidLandscapeTargeting(adUnitCodes) : []); - //store a reference of the targeting keys + // store a reference of the targeting keys targeting.map(adUnitCode => { Object.keys(adUnitCode).map(key => { adUnitCode[key].map(targetKey => { @@ -62,9 +65,28 @@ targeting.setTargeting = function(targetingConfig) { }); }; +/** + * normlizes input to a `adUnit.code` array + * @param {(string|string[])} adUnitCode [description] + * @return {string[]} AdUnit code array + */ +function getAdUnitCodes(adUnitCode) { + if (typeof adUnitCode === 'string') { + return [adUnitCode]; + } + else if (utils.isArray(adUnitCode)) { + return adUnitCode; + } + return $$PREBID_GLOBAL$$._adUnitCodes || []; +} + +/** + * Returns top bids for a given adUnit or set of adUnits. + * @param {(string|string[])} adUnitCode adUnitCode or array of adUnitCodes + * @return {[type]} [description] + */ targeting.getWinningBids = function(adUnitCode) { - // use the given adUnitCode as a filter if present or all adUnitCodes if not - const adUnitCodes = adUnitCode ? [adUnitCode] : $$PREBID_GLOBAL$$._adUnitCodes; + const adUnitCodes = getAdUnitCodes(adUnitCode); return $$PREBID_GLOBAL$$._bidsReceived .filter(bid => adUnitCodes.includes(bid.adUnitCode)) @@ -87,27 +109,28 @@ targeting.setTargetingForAst = function() { Object.keys(targeting).forEach(targetId => Object.keys(targeting[targetId]).forEach(key => { utils.logMessage(`Attempting to set targeting for targetId: ${targetId} key: ${key} value: ${targeting[targetId][key]}`); - //setKeywords supports string and array as value - if(utils.isStr(targeting[targetId][key]) || utils.isArray(targeting[targetId][key])) { + // setKeywords supports string and array as value + if (utils.isStr(targeting[targetId][key]) || utils.isArray(targeting[targetId][key])) { let keywordsObj = {}; let input = 'hb_adid'; let nKey = (key.substring(0, input.length) === input) ? key.toUpperCase() : key; keywordsObj[nKey] = targeting[targetId][key]; - window.apntag.setKeywords(targetId,keywordsObj); + window.apntag.setKeywords(targetId, keywordsObj); } }) ); }; -function getWinningBidTargeting() { - let winners = targeting.getWinningBids(); + +function getWinningBidTargeting(adUnitCodes) { + let winners = targeting.getWinningBids(adUnitCodes); let standardKeys = getStandardKeys(); winners = winners.map(winner => { return { [winner.adUnitCode]: Object.keys(winner.adserverTargeting) .filter(key => - typeof winner.sendStandardTargeting === "undefined" || + typeof winner.sendStandardTargeting === 'undefined' || winner.sendStandardTargeting || standardKeys.indexOf(key) === -1) .map(key => ({ [key.substring(0, 20)]: [winner.adserverTargeting[key]] })) @@ -118,9 +141,9 @@ function getWinningBidTargeting() { } function getStandardKeys() { - return bidmanager.getStandardBidderAdServerTargeting() // in case using a custom standard key set - .map(targeting => targeting.key) - .concat(CONSTANTS.TARGETING_KEYS).filter(uniques); // standard keys defined in the library. + return bidmanager.getStandardBidderAdServerTargeting() // in case using a custom standard key set + .map(targeting => targeting.key) + .concat(CONSTANTS.TARGETING_KEYS).filter(uniques); // standard keys defined in the library. } /** @@ -141,7 +164,6 @@ function getAlwaysUseBidTargeting(adUnitCodes) { } return { [key.substring(0, 20)]: [bid.adserverTargeting[key]] }; - }).filter(key => key) // remove empty elements }; } @@ -150,7 +172,7 @@ function getAlwaysUseBidTargeting(adUnitCodes) { } function getBidLandscapeTargeting(adUnitCodes) { - const standardKeys = CONSTANTS.TARGETING_KEYS; + const standardKeys = CONSTANTS.TARGETING_KEYS.concat(NATIVE_TARGETING_KEYS); return $$PREBID_GLOBAL$$._bidsReceived .filter(adUnitsFilter.bind(this, adUnitCodes)) diff --git a/src/url.js b/src/url.js index 9bd555d6f4e..0682ece573a 100644 --- a/src/url.js +++ b/src/url.js @@ -18,9 +18,9 @@ export function parseQS(query) { export function formatQS(query) { return Object .keys(query) - .map(k => Array.isArray(query[k]) ? - query[k].map(v => `${k}[]=${v}`).join('&') : - `${k}=${query[k]}`) + .map(k => Array.isArray(query[k]) + ? query[k].map(v => `${k}[]=${v}`).join('&') + : `${k}=${query[k]}`) .join('&'); } @@ -31,7 +31,7 @@ export function parse(url) { protocol: (parsed.protocol || '').replace(/:$/, ''), hostname: parsed.hostname, port: +parsed.port, - pathname: parsed.pathname.replace(/^(?!\/)/,'/'), + pathname: parsed.pathname.replace(/^(?!\/)/, '/'), search: parseQS(parsed.search || ''), hash: (parsed.hash || '').replace(/^#/, ''), host: parsed.host diff --git a/src/utils.js b/src/utils.js index 2ff853920fd..14f9c58f3dd 100644 --- a/src/utils.js +++ b/src/utils.js @@ -1,4 +1,4 @@ -var CONSTANTS = require('./constants.json'); +var CONSTANTS = require('./constants'); var objectType_object = 'object'; var objectType_string = 'string'; @@ -53,7 +53,7 @@ function _getUniqueIdentifierStr() { return getIncrementalInteger() + Math.random().toString(16).substr(2); } -//generate a random string (to be used as a dynamic JSONP callback) +// generate a random string (to be used as a dynamic JSONP callback) exports.getUniqueIdentifierStr = _getUniqueIdentifierStr; /** @@ -63,10 +63,9 @@ exports.getUniqueIdentifierStr = _getUniqueIdentifierStr; * https://gist.github.com/jed/982883 via node-uuid */ exports.generateUUID = function generateUUID(placeholder) { - return placeholder ? - (placeholder ^ Math.random() * 16 >> placeholder/4).toString(16) - : - ([1e7] + -1e3 + -4e3 + -8e3 + -1e11).replace(/[018]/g, generateUUID); + return placeholder + ? (placeholder ^ Math.random() * 16 >> placeholder / 4).toString(16) + : ([1e7] + -1e3 + -4e3 + -8e3 + -1e11).replace(/[018]/g, generateUUID); }; exports.getBidIdParameter = function (key, paramsObj) { @@ -85,23 +84,22 @@ exports.tryAppendQueryString = function (existingUrl, key, value) { return existingUrl; }; -//parse a query string object passed in bid params -//bid params should be an object such as {key: "value", key1 : "value1"} +// parse a query string object passed in bid params +// bid params should be an object such as {key: "value", key1 : "value1"} exports.parseQueryStringParameters = function (queryObj) { var result = ''; for (var k in queryObj) { if (queryObj.hasOwnProperty(k)) - result += k + '=' + encodeURIComponent(queryObj[k]) + '&'; + { result += k + '=' + encodeURIComponent(queryObj[k]) + '&'; } } return result; }; -//transform an AdServer targeting bids into a query string to send to the adserver +// transform an AdServer targeting bids into a query string to send to the adserver exports.transformAdServerTargetingObj = function (targeting) { // we expect to receive targeting for a single slot at a time if (targeting && Object.getOwnPropertyNames(targeting).length > 0) { - return getKeys(targeting) .map(key => `${key}=${encodeURIComponent(getValue(targeting, key))}`).join('&'); } else { @@ -114,16 +112,16 @@ exports.transformAdServerTargetingObj = function (targeting) { * @param {array[array|number]} sizeObj Input array or double array [300,250] or [[300,250], [728,90]] * @return {array[string]} Array of strings like `["300x250"]` or `["300x250", "728x90"]` */ -exports.parseSizesInput = function (sizeObj) { +export function parseSizesInput(sizeObj) { var parsedSizes = []; - //if a string for now we can assume it is a single size, like "300x250" + // if a string for now we can assume it is a single size, like "300x250" if (typeof sizeObj === objectType_string) { - //multiple sizes will be comma-separated + // multiple sizes will be comma-separated var sizes = sizeObj.split(','); - //regular expression to match strigns like 300x250 - //start of line, at least 1 number, an "x" , then at least 1 number, and the then end of the line + // regular expression to match strigns like 300x250 + // start of line, at least 1 number, an "x" , then at least 1 number, and the then end of the line var sizeRegex = /^(\d)+x(\d)+$/i; if (sizes) { for (var curSizePos in sizes) { @@ -135,30 +133,28 @@ exports.parseSizesInput = function (sizeObj) { } else if (typeof sizeObj === objectType_object) { var sizeArrayLength = sizeObj.length; - //don't process empty array + // don't process empty array if (sizeArrayLength > 0) { - //if we are a 2 item array of 2 numbers, we must be a SingleSize array + // if we are a 2 item array of 2 numbers, we must be a SingleSize array if (sizeArrayLength === 2 && typeof sizeObj[0] === objectType_number && typeof sizeObj[1] === objectType_number) { - parsedSizes.push(this.parseGPTSingleSizeArray(sizeObj)); + parsedSizes.push(parseGPTSingleSizeArray(sizeObj)); } else { - //otherwise, we must be a MultiSize array + // otherwise, we must be a MultiSize array for (var i = 0; i < sizeArrayLength; i++) { - parsedSizes.push(this.parseGPTSingleSizeArray(sizeObj[i])); + parsedSizes.push(parseGPTSingleSizeArray(sizeObj[i])); } - } } } return parsedSizes; - }; -//parse a GPT style sigle size array, (i.e [300,250]) -//into an AppNexus style string, (i.e. 300x250) -exports.parseGPTSingleSizeArray = function (singleSize) { - //if we aren't exactly 2 items in this array, it is invalid - if (this.isArray(singleSize) && singleSize.length === 2 && (!isNaN(singleSize[0]) && !isNaN(singleSize[1]))) { +// parse a GPT style sigle size array, (i.e [300,250]) +// into an AppNexus style string, (i.e. 300x250) +export function parseGPTSingleSizeArray(singleSize) { + // if we aren't exactly 2 items in this array, it is invalid + if (exports.isArray(singleSize) && singleSize.length === 2 && (!isNaN(singleSize[0]) && !isNaN(singleSize[1]))) { return singleSize[0] + 'x' + singleSize[1]; } }; @@ -344,7 +340,7 @@ exports.isNumber = function(object) { exports.isEmpty = function (object) { if (!object) return true; if (this.isArray(object) || this.isStr(object)) { - return !(object.length > 0); // jshint ignore:line + return !(object.length > 0); } for (var k in object) { @@ -360,7 +356,7 @@ exports.isEmpty = function (object) { * @returns {boolean} if string is empty */ exports.isEmptyStr = function(str) { - return this.isStr(str) && (!str || 0 === str.length); + return this.isStr(str) && (!str || str.length === 0); }; /** @@ -410,7 +406,7 @@ exports.indexOf = (function () { } // ie8 no longer supported - //return polyfills.indexOf; + // return polyfills.indexOf; }()); /** @@ -439,10 +435,17 @@ var hasOwn = function (objectToCheck, propertyToCheckFor) { } }; -var insertElement = function(elm) { - let elToAppend = document.getElementsByTagName('head'); - try{ - elToAppend = elToAppend.length ? elToAppend : document.getElementsByTagName('body'); +exports.insertElement = function(elm, doc, target) { + doc = doc || document; + let elToAppend; + if (target) { + elToAppend = doc.getElementsByTagName(target); + } + else { + elToAppend = doc.getElementsByTagName('head'); + } + try { + elToAppend = elToAppend.length ? elToAppend : doc.getElementsByTagName('body'); if (elToAppend.length) { elToAppend = elToAppend[0]; elToAppend.insertBefore(elm, elToAppend.firstChild); @@ -452,7 +455,7 @@ var insertElement = function(elm) { exports.insertPixel = function (url) { const img = new Image(); - img.id = this.getUniqueIdentifierStr(); + img.id = _getUniqueIdentifierStr(); img.src = url; img.height = 0; img.width = 0; @@ -460,10 +463,10 @@ exports.insertPixel = function (url) { img.onload = function() { try { this.parentNode.removeChild(this); - } catch(e) { + } catch (e) { } }; - insertElement(img); + exports.insertElement(img); }; /** @@ -475,8 +478,8 @@ exports.insertCookieSyncIframe = function(url, encodeUri) { let iframeHtml = this.createTrackPixelIframeHtml(url, encodeUri); let div = document.createElement('div'); div.innerHTML = iframeHtml; - let iframe = div.firstChild; - insertElement(iframe); + let iframe = div.firstChild; + exports.insertElement(iframe); }; /** @@ -505,7 +508,7 @@ exports.createTrackPixelIframeHtml = function (url, encodeUri = true) { if (!url) { return ''; } - if(encodeUri) { + if (encodeUri) { url = encodeURI(url); } @@ -543,7 +546,7 @@ exports.getValueString = function(param, val, defaultValue) { if (val === undefined || val === null) { return defaultValue; } - if (this.isStr(val) ) { + if (this.isStr(val)) { return val; } if (this.isNumber(val)) { @@ -627,7 +630,7 @@ export function adUnitsFilter(filter, bid) { * @param {HTMLDocument} doc document to check support of 'srcdoc' */ export function isSrcdocSupported(doc) { - //Firefox is excluded due to https://bugzilla.mozilla.org/show_bug.cgi?id=1265961 + // Firefox is excluded due to https://bugzilla.mozilla.org/show_bug.cgi?id=1265961 return doc.defaultView && doc.defaultView.frameElement && 'srcdoc' in doc.defaultView.frameElement && !/firefox/i.test(navigator.userAgent); } @@ -649,13 +652,17 @@ export function isSafariBrowser() { } export function replaceAuctionPrice(str, cpm) { - if(!str) return; + if (!str) return; return str.replace(/\$\{AUCTION_PRICE\}/g, cpm); } +export function getBidderRequestAllAdUnits(bidder) { + return $$PREBID_GLOBAL$$._bidsRequested.find(request => request.bidderCode === bidder); +} + export function getBidderRequest(bidder, adUnitCode) { return $$PREBID_GLOBAL$$._bidsRequested.find(request => { return request.bids - .filter(bid => bid.bidder === bidder && bid.placementCode === adUnitCode).length > 0; + .filter(bid => bid.bidder === bidder && bid.placementCode === adUnitCode).length > 0; }) || { start: null, requestId: null }; } diff --git a/src/videoCache.js b/src/videoCache.js new file mode 100644 index 00000000000..a3b7f66e4fe --- /dev/null +++ b/src/videoCache.js @@ -0,0 +1,114 @@ +/** + * This module interacts with the server used to cache video ad content to be restored later. + * At a high level, the expected workflow goes like this: + * + * - Request video ads from Bidders + * - Generate IDs for each valid bid, and cache the key/value pair on the server. + * - Return these IDs so that publishers can use them to fetch the bids later. + * + * This trickery helps integrate with ad servers, which set character limits on request params. + */ + +import { ajax } from './ajax'; + +const PUT_URL = 'https://prebid.adnxs.com/pbc/v1/cache' + +/** + * These are the properties required on a Bid in order to cache and retrieve it. + * + * @typedef {object} CacheableBid + * @property {string} vastUrl A URL which loads some valid VAST XML. + */ + +/** + * Function which wraps a URI that serves VAST XML, so that it can be loaded. + * + * @param {string} uri The URI where the VAST content can be found. + * @return A VAST URL which loads XML from the given URI. + */ +function wrapURI(uri) { + // Technically, this is vulnerable to cross-script injection by sketchy vastUrl bids. + // We could make sure it's a valid URI... but since we're loading VAST XML from the + // URL they provide anyway, that's probably not a big deal. + return ` + + + prebid.org wrapper + + + + + + `; +} + +/** + * Wraps a bid in the format expected by the prebid-server endpoints, or returns null if + * the bid can't be converted cleanly. + * + * @param {CacheableBid} bid + */ +function toStorageRequest(bid) { + return { + type: 'xml', + value: wrapURI(bid.vastUrl) + }; +} + + +/** + * A function which should be called with the results of the storage operation. + * + * @callback videoCacheStoreCallback + * + * @param {Error} [error] The error, if one occurred. + * @param {?string[]} uuids An array of unique IDs. The array will have one element for each bid we were asked + * to store. It may include null elements if some of the bids were malformed, or an error occurred. + * Each non-null element in this array is a valid input into the retrieve function, which will fetch + * some VAST XML which can be used to render this bid's ad. + */ + +/** + * A function which bridges the APIs between the videoCacheStoreCallback and our ajax function's API. + * + * @param {videoCacheStoreCallback} done A callback to the "store" function. + * @return {Function} A callback which interprets the cache server's responses, and makes up the right + * arguments for our callback. + */ +function shimStorageCallback(done) { + return { + success: function(responseBody) { + let ids; + try { + ids = JSON.parse(responseBody).responses + } + catch (e) { + done(e, []); + return; + } + + done(null, ids); + }, + error: function(statusText, responseBody) { + done(new Error(`Error storing video ad in the cache: ${statusText}: ${JSON.stringify(responseBody)}`), []); + } + } +} + +/** + * If the given bid is for a Video ad, generate a unique ID and cache it somewhere server-side. + * + * @param {CacheableBid[]} bids A list of bid objects which should be cached. + * @param {videoCacheStoreCallback} [done] An optional callback which should be executed after + * the data has been stored in the cache. + */ +export function store(bids, done) { + const requestData = { + puts: bids.map(toStorageRequest) + }; + + ajax(PUT_URL, shimStorageCallback(done), JSON.stringify(requestData), { + contentType: 'text/plain', + withCredentials: true + }); +} diff --git a/test/.eslintrc.js b/test/.eslintrc.js new file mode 100644 index 00000000000..29f57acb446 --- /dev/null +++ b/test/.eslintrc.js @@ -0,0 +1,50 @@ +module.exports = { + "env": { + "browser": true, + "mocha": true + }, + "extends": "standard", + "globals": { + "$$PREBID_GLOBAL$$": false + }, + "parserOptions": { + "sourceType": "module" + }, + "rules": { + "comma-dangle": "off", + "semi": "off", + "space-before-function-paren": "off", + + // Exceptions below this line are temporary, so that eslint can be added into the CI process. + // Violations of these styles should be fixed, and the exceptions removed over time. + // + // See Issue #1111. + "camelcase": "off", + "eqeqeq": "off", + "no-mixed-spaces-and-tabs": "off", + "no-tabs": "off", + "no-unused-expressions": "off", + "import/no-duplicates": "off", + "no-template-curly-in-string": "off", + "new-cap": "off", + "no-global-assign": "off", + "no-path-concat": "off", + "no-redeclare": "off", + "no-new-object": "off", + "no-array-constructor": "off", + "node/no-deprecated-api": "off", + "no-cond-assign": "off", + "no-sequences": "off", + "no-eval": "off", + "no-new": "off", + "no-return-assign": "off", + "no-undef": "off", + "no-unused-vars": "off", + "no-use-before-define": "off", + "no-useless-escape": "off", + "one-var": "off", + "standard/array-bracket-even-spacing": "off", + "standard/no-callback-literal": "off", + "standard/object-curly-even-spacing": "off" + } +}; diff --git a/test/fixtures/config.json b/test/fixtures/config.json index da00ce5478b..053efe15f76 100644 --- a/test/fixtures/config.json +++ b/test/fixtures/config.json @@ -9,4 +9,4 @@ "/123456/header-bid-tag-1", "/123456/header-bid-tag-2" ] -} \ No newline at end of file +} diff --git a/test/fixtures/fixtures.js b/test/fixtures/fixtures.js index 202d95b402b..e1cdbed8ab6 100644 --- a/test/fixtures/fixtures.js +++ b/test/fixtures/fixtures.js @@ -3,18 +3,18 @@ export function getBidRequests() { return [ { - "bidderCode": "appnexus", - "requestId": "1863e370099523", - "bidderRequestId": "2946b569352ef2", - "bids": [ + 'bidderCode': 'appnexus', + 'requestId': '1863e370099523', + 'bidderRequestId': '2946b569352ef2', + 'bids': [ { - "bidder": "appnexus", - "params": { - "placementId": "4799418", - "test": "me" + 'bidder': 'appnexus', + 'params': { + 'placementId': '4799418', + 'test': 'me' }, - "placementCode": "/19968336/header-bid-tag1", - "sizes": [ + 'placementCode': '/19968336/header-bid-tag1', + 'sizes': [ [ 728, 90 @@ -24,20 +24,20 @@ export function getBidRequests() { 90 ] ], - "bidId": "392b5a6b05d648", - "bidderRequestId": "2946b569352ef2", - "requestId": "1863e370099523", - "startTime": 1462918897462, - "status": 1, - "transactionId": "fsafsa" + 'bidId': '392b5a6b05d648', + 'bidderRequestId': '2946b569352ef2', + 'requestId': '1863e370099523', + 'startTime': 1462918897462, + 'status': 1, + 'transactionId': 'fsafsa' }, { - "bidder": "appnexus", - "params": { - "placementId": "4799418" + 'bidder': 'appnexus', + 'params': { + 'placementId': '4799418' }, - "placementCode": "/19968336/header-bid-tag-0", - "sizes": [ + 'placementCode': '/19968336/header-bid-tag-0', + 'sizes': [ [ 300, 250 @@ -47,29 +47,29 @@ export function getBidRequests() { 600 ] ], - "bidId": "4dccdc37746135", - "bidderRequestId": "2946b569352ef2", - "requestId": "1863e370099523", - "startTime": 1462918897463, - "status": 1, - "transactionId": "fsafsa" + 'bidId': '4dccdc37746135', + 'bidderRequestId': '2946b569352ef2', + 'requestId': '1863e370099523', + 'startTime': 1462918897463, + 'status': 1, + 'transactionId': 'fsafsa' } ], - "start": 1462918897460 + 'start': 1462918897460 }, { - "bidderCode": "pubmatic", - "requestId": "1863e370099523", - "bidderRequestId": "5e1525bae3eb11", - "bids": [ + 'bidderCode': 'pubmatic', + 'requestId': '1863e370099523', + 'bidderRequestId': '5e1525bae3eb11', + 'bids': [ { - "bidder": "pubmatic", - "params": { - "publisherId": 39741, - "adSlot": "39620189@300x250" + 'bidder': 'pubmatic', + 'params': { + 'publisherId': 39741, + 'adSlot': '39620189@300x250' }, - "placementCode": "/19968336/header-bid-tag-0", - "sizes": [ + 'placementCode': '/19968336/header-bid-tag-0', + 'sizes': [ [ 300, 250 @@ -79,46 +79,46 @@ export function getBidRequests() { 600 ] ], - "bidId": "6d11aa2d5b3659", - "bidderRequestId": "5e1525bae3eb11", - "requestId": "1863e370099523", - "transactionId": "fsafsa" + 'bidId': '6d11aa2d5b3659', + 'bidderRequestId': '5e1525bae3eb11', + 'requestId': '1863e370099523', + 'transactionId': 'fsafsa' } ], - "start": 1462918897463 + 'start': 1462918897463 }, { - "bidderCode": "rubicon", - "requestId": "1863e370099523", - "bidderRequestId": "8778750ee15a77", - "bids": [ + 'bidderCode': 'rubicon', + 'requestId': '1863e370099523', + 'bidderRequestId': '8778750ee15a77', + 'bids': [ { - "bidder": "rubicon", - "params": { - "accountId": "14062", - "siteId": "70608", - "zoneId": "335918", - "userId": "12346", - "keywords": [ - "a", - "b", - "c" + 'bidder': 'rubicon', + 'params': { + 'accountId': '14062', + 'siteId': '70608', + 'zoneId': '335918', + 'userId': '12346', + 'keywords': [ + 'a', + 'b', + 'c' ], - "inventory": { - "rating": "5-star", - "prodtype": "tech" + 'inventory': { + 'rating': '5-star', + 'prodtype': 'tech' }, - "visitor": { - "ucat": "new", - "search": "iphone" + 'visitor': { + 'ucat': 'new', + 'search': 'iphone' }, - "sizes": [ + 'sizes': [ 15, 10 ], }, - "placementCode": "/19968336/header-bid-tag-0", - "sizes": [ + 'placementCode': '/19968336/header-bid-tag-0', + 'sizes': [ [ 300, 250 @@ -128,26 +128,26 @@ export function getBidRequests() { 600 ] ], - "bidId": "96aff279720d39", - "bidderRequestId": "8778750ee15a77", - "requestId": "1863e370099523", - "transactionId": "fsafsa" + 'bidId': '96aff279720d39', + 'bidderRequestId': '8778750ee15a77', + 'requestId': '1863e370099523', + 'transactionId': 'fsafsa' } ], - "start": 1462918897474 + 'start': 1462918897474 }, { - "bidderCode": "triplelift", - "requestId": "1863e370099523", - "bidderRequestId": "107f5e6e98dcf09", - "bids": [ + 'bidderCode': 'triplelift', + 'requestId': '1863e370099523', + 'bidderRequestId': '107f5e6e98dcf09', + 'bids': [ { - "bidder": "triplelift", - "params": { - "inventoryCode": "sortable_all_right_sports" + 'bidder': 'triplelift', + 'params': { + 'inventoryCode': 'sortable_all_right_sports' }, - "placementCode": "/19968336/header-bid-tag-0", - "sizes": [ + 'placementCode': '/19968336/header-bid-tag-0', + 'sizes': [ [ 300, 250 @@ -157,27 +157,27 @@ export function getBidRequests() { 600 ] ], - "bidId": "1144e2f0de84363", - "bidderRequestId": "107f5e6e98dcf09", - "requestId": "1863e370099523", - "startTime": 1462918897477, - "transactionId": "fsafsa" + 'bidId': '1144e2f0de84363', + 'bidderRequestId': '107f5e6e98dcf09', + 'requestId': '1863e370099523', + 'startTime': 1462918897477, + 'transactionId': 'fsafsa' } ], - "start": 1462918897475 + 'start': 1462918897475 }, { - "bidderCode": "brightcom", - "requestId": "1863e370099523", - "bidderRequestId": "12eeded736650b4", - "bids": [ + 'bidderCode': 'brightcom', + 'requestId': '1863e370099523', + 'bidderRequestId': '12eeded736650b4', + 'bids': [ { - "bidder": "brightcom", - "params": { - "tagId": 16577 + 'bidder': 'brightcom', + 'params': { + 'tagId': 16577 }, - "placementCode": "/19968336/header-bid-tag-0", - "sizes": [ + 'placementCode': '/19968336/header-bid-tag-0', + 'sizes': [ [ 300, 250 @@ -187,27 +187,27 @@ export function getBidRequests() { 600 ] ], - "bidId": "135e89c039705da", - "bidderRequestId": "12eeded736650b4", - "requestId": "1863e370099523", - "status": 1, - "transactionId": "fsafsa" + 'bidId': '135e89c039705da', + 'bidderRequestId': '12eeded736650b4', + 'requestId': '1863e370099523', + 'status': 1, + 'transactionId': 'fsafsa' } ], - "start": 1462918897477 + 'start': 1462918897477 }, { - "bidderCode": "brealtime", - "requestId": "1863e370099523", - "bidderRequestId": "167c4d79b615948", - "bids": [ + 'bidderCode': 'brealtime', + 'requestId': '1863e370099523', + 'bidderRequestId': '167c4d79b615948', + 'bids': [ { - "bidder": "brealtime", - "params": { - "placementId": "4799418" + 'bidder': 'brealtime', + 'params': { + 'placementId': '4799418' }, - "placementCode": "/19968336/header-bid-tag-0", - "sizes": [ + 'placementCode': '/19968336/header-bid-tag-0', + 'sizes': [ [ 300, 250 @@ -217,28 +217,28 @@ export function getBidRequests() { 600 ] ], - "bidId": "17dd1d869bed44e", - "bidderRequestId": "167c4d79b615948", - "requestId": "1863e370099523", - "startTime": 1462918897480, - "status": 1, - "transactionId": "fsafsa" + 'bidId': '17dd1d869bed44e', + 'bidderRequestId': '167c4d79b615948', + 'requestId': '1863e370099523', + 'startTime': 1462918897480, + 'status': 1, + 'transactionId': 'fsafsa' } ], - "start": 1462918897479 + 'start': 1462918897479 }, { - "bidderCode": "pagescience", - "requestId": "1863e370099523", - "bidderRequestId": "18bed198c172a69", - "bids": [ + 'bidderCode': 'pagescience', + 'requestId': '1863e370099523', + 'bidderRequestId': '18bed198c172a69', + 'bids': [ { - "bidder": "pagescience", - "params": { - "placementId": "4799418" + 'bidder': 'pagescience', + 'params': { + 'placementId': '4799418' }, - "placementCode": "/19968336/header-bid-tag-0", - "sizes": [ + 'placementCode': '/19968336/header-bid-tag-0', + 'sizes': [ [ 300, 250 @@ -248,28 +248,28 @@ export function getBidRequests() { 600 ] ], - "bidId": "192c8c1df0f5d1d", - "bidderRequestId": "18bed198c172a69", - "requestId": "1863e370099523", - "startTime": 1462918897481, - "status": 1, - "transactionId": "fsafsa" + 'bidId': '192c8c1df0f5d1d', + 'bidderRequestId': '18bed198c172a69', + 'requestId': '1863e370099523', + 'startTime': 1462918897481, + 'status': 1, + 'transactionId': 'fsafsa' } ], - "start": 1462918897480 + 'start': 1462918897480 }, { - "bidderCode": "amazon", - "requestId": "1863e370099523", - "bidderRequestId": "20d0d30333715a7", - "bids": [ + 'bidderCode': 'amazon', + 'requestId': '1863e370099523', + 'bidderRequestId': '20d0d30333715a7', + 'bids': [ { - "bidder": "amazon", - "params": { - "aId": 3080 + 'bidder': 'amazon', + 'params': { + 'aId': 3080 }, - "placementCode": "/19968336/header-bid-tag-0", - "sizes": [ + 'placementCode': '/19968336/header-bid-tag-0', + 'sizes': [ [ 300, 250 @@ -279,13 +279,13 @@ export function getBidRequests() { 600 ] ], - "bidId": "21ae8131ec04f6e", - "bidderRequestId": "20d0d30333715a7", - "requestId": "1863e370099523", - "transactionId": "fsafsa" + 'bidId': '21ae8131ec04f6e', + 'bidderRequestId': '20d0d30333715a7', + 'requestId': '1863e370099523', + 'transactionId': 'fsafsa' } ], - "start": 1462918897482 + 'start': 1462918897482 } ]; } @@ -293,227 +293,227 @@ export function getBidRequests() { export function getBidResponses() { return [ { - "bidderCode": "triplelift", - "width": 0, - "height": 0, - "statusMessage": "Bid available", - "adId": "222bb26f9e8bd", - "cpm": 0.112256, - "ad": "", - "responseTimestamp": 1462919239337, - "requestTimestamp": 1462919238936, - "bidder": "triplelift", - "adUnitCode": "/19968336/header-bid-tag-0", - "timeToRespond": 401, - "pbLg": "0.00", - "pbMg": "0.10", - "pbHg": "0.11", - "pbAg": "0.10", - "size": "0x0", - "requestId": 123456, - "adserverTargeting": { - "hb_bidder": "triplelift", - "hb_adid": "222bb26f9e8bd", - "hb_pb": "10.00", - "hb_size": "0x0", - "foobar": "0x0" + 'bidderCode': 'triplelift', + 'width': 0, + 'height': 0, + 'statusMessage': 'Bid available', + 'adId': '222bb26f9e8bd', + 'cpm': 0.112256, + 'ad': "", + 'responseTimestamp': 1462919239337, + 'requestTimestamp': 1462919238936, + 'bidder': 'triplelift', + 'adUnitCode': '/19968336/header-bid-tag-0', + 'timeToRespond': 401, + 'pbLg': '0.00', + 'pbMg': '0.10', + 'pbHg': '0.11', + 'pbAg': '0.10', + 'size': '0x0', + 'requestId': 123456, + 'adserverTargeting': { + 'hb_bidder': 'triplelift', + 'hb_adid': '222bb26f9e8bd', + 'hb_pb': '10.00', + 'hb_size': '0x0', + 'foobar': '0x0' } }, { - "bidderCode": "appnexus", - "width": 300, - "height": 250, - "statusMessage": "Bid available", - "adId": "233bcbee889d46d", - "creative_id": 29681110, - "cpm": 10, - "adUrl": "http://lax1-ib.adnxs.com/ab?e=wqT_3QL8BKh8AgAAAwDWAAUBCMjAybkFEMLLiJWTu9PsVxjL84KE1tzG-kkgASotCQAAAQII4D8RAQcQAADgPxkJCQjwPyEJCQjgPykRCaAwuvekAji-B0C-B0gCUNbLkw5YweAnYABokUB4190DgAEBigEDVVNEkgUG8FKYAawCoAH6AagBAbABALgBAcABA8gBANABANgBAOABAPABAIoCOnVmKCdhJywgNDk0NDcyLCAxNDYyOTE5MjQwKTt1ZigncicsIDI5NjgxMTEwLDIeAPBskgLZASFmU21rZ0FpNjBJY0VFTmJMa3c0WUFDREI0Q2N3QURnQVFBUkl2Z2RRdXZla0FsZ0FZSk1IYUFCd0EzZ0RnQUVEaUFFRGtBRUJtQUVCb0FFQnFBRURzQUVBdVFFQUFBQUFBQURnUDhFQgkMTEFBNERfSkFRMkxMcEVUMU93XzJRFSggd1AtQUJBUFVCBSxASmdDaW9EVTJnV2dBZ0MxQWcBFgRDOQkIqERBQWdQSUFnUFFBZ1BZQWdQZ0FnRG9BZ0Q0QWdDQUF3RS6aAiUhV1FrbmI63AAcd2VBbklBUW8JXPCVVS7YAugH4ALH0wHqAh9odHRwOi8vcHJlYmlkLm9yZzo5OTk5L2dwdC5odG1sgAMAiAMBkAMAmAMFoAMBqgMAsAMAuAMAwAOsAsgDANgDAOADAOgDAPgDA4AEAJIEBC9qcHSYBACiBAoxMC4xLjEzLjM3qAQAsgQICAAQABgAIAC4BADABADIBADSBAoxMC4wLjg1Ljkx&s=1bf15e8cdc7c0c8c119614c6386ab1496560da39&referrer=http%3A%2F%2Fprebid.org%3A9999%2Fgpt.html", - "responseTimestamp": 1462919239340, - "requestTimestamp": 1462919238919, - "bidder": "appnexus", - "adUnitCode": "/19968336/header-bid-tag-0", - "timeToRespond": 421, - "pbLg": "5.00", - "pbMg": "10.00", - "pbHg": "10.00", - "pbAg": "10.00", - "size": "300x250", - "alwaysUseBid": true, - "requestId": 123456, - "adserverTargeting": { - "hb_bidder": "appnexus", - "hb_adid": "233bcbee889d46d", - "hb_pb": "10.00", - "hb_size": "300x250", - "foobar": "300x250" + 'bidderCode': 'appnexus', + 'width': 300, + 'height': 250, + 'statusMessage': 'Bid available', + 'adId': '233bcbee889d46d', + 'creative_id': 29681110, + 'cpm': 10, + 'adUrl': 'http://lax1-ib.adnxs.com/ab?e=wqT_3QL8BKh8AgAAAwDWAAUBCMjAybkFEMLLiJWTu9PsVxjL84KE1tzG-kkgASotCQAAAQII4D8RAQcQAADgPxkJCQjwPyEJCQjgPykRCaAwuvekAji-B0C-B0gCUNbLkw5YweAnYABokUB4190DgAEBigEDVVNEkgUG8FKYAawCoAH6AagBAbABALgBAcABA8gBANABANgBAOABAPABAIoCOnVmKCdhJywgNDk0NDcyLCAxNDYyOTE5MjQwKTt1ZigncicsIDI5NjgxMTEwLDIeAPBskgLZASFmU21rZ0FpNjBJY0VFTmJMa3c0WUFDREI0Q2N3QURnQVFBUkl2Z2RRdXZla0FsZ0FZSk1IYUFCd0EzZ0RnQUVEaUFFRGtBRUJtQUVCb0FFQnFBRURzQUVBdVFFQUFBQUFBQURnUDhFQgkMTEFBNERfSkFRMkxMcEVUMU93XzJRFSggd1AtQUJBUFVCBSxASmdDaW9EVTJnV2dBZ0MxQWcBFgRDOQkIqERBQWdQSUFnUFFBZ1BZQWdQZ0FnRG9BZ0Q0QWdDQUF3RS6aAiUhV1FrbmI63AAcd2VBbklBUW8JXPCVVS7YAugH4ALH0wHqAh9odHRwOi8vcHJlYmlkLm9yZzo5OTk5L2dwdC5odG1sgAMAiAMBkAMAmAMFoAMBqgMAsAMAuAMAwAOsAsgDANgDAOADAOgDAPgDA4AEAJIEBC9qcHSYBACiBAoxMC4xLjEzLjM3qAQAsgQICAAQABgAIAC4BADABADIBADSBAoxMC4wLjg1Ljkx&s=1bf15e8cdc7c0c8c119614c6386ab1496560da39&referrer=http%3A%2F%2Fprebid.org%3A9999%2Fgpt.html', + 'responseTimestamp': 1462919239340, + 'requestTimestamp': 1462919238919, + 'bidder': 'appnexus', + 'adUnitCode': '/19968336/header-bid-tag-0', + 'timeToRespond': 421, + 'pbLg': '5.00', + 'pbMg': '10.00', + 'pbHg': '10.00', + 'pbAg': '10.00', + 'size': '300x250', + 'alwaysUseBid': true, + 'requestId': 123456, + 'adserverTargeting': { + 'hb_bidder': 'appnexus', + 'hb_adid': '233bcbee889d46d', + 'hb_pb': '10.00', + 'hb_size': '300x250', + 'foobar': '300x250' } }, { - "bidderCode": "appnexus", - "width": 728, - "height": 90, - "statusMessage": "Bid available", - "adId": "24bd938435ec3fc", - "creative_id": 33989846, - "cpm": 10, - "adUrl": "http://lax1-ib.adnxs.com/ab?e=wqT_3QLyBKhyAgAAAwDWAAUBCMjAybkFEOOryfjI7rGNWhjL84KE1tzG-kkgASotCQAAAQII4D8RAQcQAADgPxkJCQjwPyEJCQjgPykRCaAwuvekAji-B0C-B0gCUNbJmhBYweAnYABokUB4mt0CgAEBigEDVVNEkgUG8ECYAdgFoAFaqAEBsAEAuAEBwAEDyAEA0AEA2AEA4AEA8AEAigI6dWYoJ2EnLCA0OTQ0NzIsIDE0NjI5MTkyNDApOwEcLHInLCAzMzk4OTg0NjYeAPBvkgLNASFwU2Y1YUFpNjBJY0VFTmJKbWhBWUFDREI0Q2N3QURnQVFBUkl2Z2RRdXZla0FsZ0FZSk1IYUFCd3lnNTRDb0FCcGh5SUFRcVFBUUdZQVFHZ0FRR29BUU93QVFDNUFRQUFBQUFBQU9BX3dRRQkMSEFEZ1A4a0JJNTJDbGs5VjB6X1oVKCRQQV80QUVBOVFFBSw8bUFLS2dNQ0NENkFDQUxVQwUVBEwwCQh0T0FDQU9nQ0FQZ0NBSUFEQVEuLpoCJSFfZ2lqYXdpMtAA8KZ3ZUFuSUFRb2lvREFnZzgu2ALoB-ACx9MB6gIfaHR0cDovL3ByZWJpZC5vcmc6OTk5OS9ncHQuaHRtbIADAIgDAZADAJgDBaADAaoDALADALgDAMADrALIAwDYAwDgAwDoAwD4AwOABACSBAQvanB0mAQAogQKMTAuMS4xMy4zN6gEi-wJsgQICAAQABgAIAC4BADABADIBADSBAsxMC4wLjgwLjI0MA..&s=1f584d32c2d7ae3ce3662cfac7ca24e710bc7fd0&referrer=http%3A%2F%2Fprebid.org%3A9999%2Fgpt.html", - "responseTimestamp": 1462919239342, - "requestTimestamp": 1462919238919, - "bidder": "appnexus", - "adUnitCode": "/19968336/header-bid-tag1", - "timeToRespond": 423, - "pbLg": "5.00", - "pbMg": "10.00", - "pbHg": "10.00", - "pbAg": "10.00", - "size": "728x90", - "alwaysUseBid": true, - "requestId": 123456, - "adserverTargeting": { - "hb_bidder": "appnexus", - "hb_adid": "24bd938435ec3fc", - "hb_pb": "10.00", - "hb_size": "728x90", - "foobar": "728x90" + 'bidderCode': 'appnexus', + 'width': 728, + 'height': 90, + 'statusMessage': 'Bid available', + 'adId': '24bd938435ec3fc', + 'creative_id': 33989846, + 'cpm': 10, + 'adUrl': 'http://lax1-ib.adnxs.com/ab?e=wqT_3QLyBKhyAgAAAwDWAAUBCMjAybkFEOOryfjI7rGNWhjL84KE1tzG-kkgASotCQAAAQII4D8RAQcQAADgPxkJCQjwPyEJCQjgPykRCaAwuvekAji-B0C-B0gCUNbJmhBYweAnYABokUB4mt0CgAEBigEDVVNEkgUG8ECYAdgFoAFaqAEBsAEAuAEBwAEDyAEA0AEA2AEA4AEA8AEAigI6dWYoJ2EnLCA0OTQ0NzIsIDE0NjI5MTkyNDApOwEcLHInLCAzMzk4OTg0NjYeAPBvkgLNASFwU2Y1YUFpNjBJY0VFTmJKbWhBWUFDREI0Q2N3QURnQVFBUkl2Z2RRdXZla0FsZ0FZSk1IYUFCd3lnNTRDb0FCcGh5SUFRcVFBUUdZQVFHZ0FRR29BUU93QVFDNUFRQUFBQUFBQU9BX3dRRQkMSEFEZ1A4a0JJNTJDbGs5VjB6X1oVKCRQQV80QUVBOVFFBSw8bUFLS2dNQ0NENkFDQUxVQwUVBEwwCQh0T0FDQU9nQ0FQZ0NBSUFEQVEuLpoCJSFfZ2lqYXdpMtAA8KZ3ZUFuSUFRb2lvREFnZzgu2ALoB-ACx9MB6gIfaHR0cDovL3ByZWJpZC5vcmc6OTk5OS9ncHQuaHRtbIADAIgDAZADAJgDBaADAaoDALADALgDAMADrALIAwDYAwDgAwDoAwD4AwOABACSBAQvanB0mAQAogQKMTAuMS4xMy4zN6gEi-wJsgQICAAQABgAIAC4BADABADIBADSBAsxMC4wLjgwLjI0MA..&s=1f584d32c2d7ae3ce3662cfac7ca24e710bc7fd0&referrer=http%3A%2F%2Fprebid.org%3A9999%2Fgpt.html', + 'responseTimestamp': 1462919239342, + 'requestTimestamp': 1462919238919, + 'bidder': 'appnexus', + 'adUnitCode': '/19968336/header-bid-tag1', + 'timeToRespond': 423, + 'pbLg': '5.00', + 'pbMg': '10.00', + 'pbHg': '10.00', + 'pbAg': '10.00', + 'size': '728x90', + 'alwaysUseBid': true, + 'requestId': 123456, + 'adserverTargeting': { + 'hb_bidder': 'appnexus', + 'hb_adid': '24bd938435ec3fc', + 'hb_pb': '10.00', + 'hb_size': '728x90', + 'foobar': '728x90' } }, { - "bidderCode": "pagescience", - "width": 300, - "height": 250, - "statusMessage": "Bid available", - "adId": "25bedd4813632d7", - "creative_id": 29681110, - "cpm": 0.5, - "adUrl": "http://lax1-ib.adnxs.com/ab?e=wqT_3QLzBKhzAgAAAwDWAAUBCMjAybkFEM7fioW41qjIQRjL84KE1tzG-kkgASotCQAAAQII4D8RAQcQAADgPxkJCQjwPyEJCQjgPykRCaAwuvekAji-B0C-B0gCUNbLkw5YweAnYABokUB4yIsEgAEBigEDVVNEkgUG8FKYAawCoAH6AagBAbABALgBAcABA8gBANABANgBAOABAPABAIoCOnVmKCdhJywgNDk0NDcyLCAxNDYyOTE5MjQwKTt1ZigncicsIDI5NjgxMTEwLDIeAPBvkgLNASFfeWVLYndpNjBJY0VFTmJMa3c0WUFDREI0Q2N3QURnQVFBUkl2Z2RRdXZla0FsZ0FZSk1IYUFCdzNBMTRDb0FCcGh5SUFRcVFBUUdZQVFHZ0FRR29BUU93QVFDNUFRQUFBQUFBQU9BX3dRRQkMSEFEZ1A4a0JSR3RLaGp1UTFEX1oVKCRQQV80QUVBOVFFBSw8bUFLS2dQVFNES0FDQUxVQwUVBEwwCQhwT0FDQU9nQ0FQZ0NBSUFEQVEuLpoCJSFlQWwtYkE20ADwpndlQW5JQVFvaW9EMDBndy7YAugH4ALH0wHqAh9odHRwOi8vcHJlYmlkLm9yZzo5OTk5L2dwdC5odG1sgAMAiAMBkAMAmAMFoAMBqgMAsAMAuAMAwAOsAsgDANgDAOADAOgDAPgDA4AEAJIEBC9qcHSYBACiBAoxMC4xLjEzLjM3qASL7AmyBAgIABAAGAAgALgEAMAEAMgEANIECzEwLjAuOTMuMjAy&s=1fd8d5650fa1fb8d918a2f403d6a1f97c10d7ec2&referrer=http%3A%2F%2Fprebid.org%3A9999%2Fgpt.html", - "responseTimestamp": 1462919239343, - "requestTimestamp": 1462919238943, - "bidder": "pagescience", - "adUnitCode": "/19968336/header-bid-tag-0", - "timeToRespond": 400, - "pbLg": "0.50", - "pbMg": "0.50", - "pbHg": "0.50", - "pbAg": "0.50", - "size": "300x250", - "requestId": 123456, - "adserverTargeting": { - "hb_bidder": "pagescience", - "hb_adid": "25bedd4813632d7", - "hb_pb": "10.00", - "hb_size": "300x250", - "foobar": "300x250" + 'bidderCode': 'pagescience', + 'width': 300, + 'height': 250, + 'statusMessage': 'Bid available', + 'adId': '25bedd4813632d7', + 'creative_id': 29681110, + 'cpm': 0.5, + 'adUrl': 'http://lax1-ib.adnxs.com/ab?e=wqT_3QLzBKhzAgAAAwDWAAUBCMjAybkFEM7fioW41qjIQRjL84KE1tzG-kkgASotCQAAAQII4D8RAQcQAADgPxkJCQjwPyEJCQjgPykRCaAwuvekAji-B0C-B0gCUNbLkw5YweAnYABokUB4yIsEgAEBigEDVVNEkgUG8FKYAawCoAH6AagBAbABALgBAcABA8gBANABANgBAOABAPABAIoCOnVmKCdhJywgNDk0NDcyLCAxNDYyOTE5MjQwKTt1ZigncicsIDI5NjgxMTEwLDIeAPBvkgLNASFfeWVLYndpNjBJY0VFTmJMa3c0WUFDREI0Q2N3QURnQVFBUkl2Z2RRdXZla0FsZ0FZSk1IYUFCdzNBMTRDb0FCcGh5SUFRcVFBUUdZQVFHZ0FRR29BUU93QVFDNUFRQUFBQUFBQU9BX3dRRQkMSEFEZ1A4a0JSR3RLaGp1UTFEX1oVKCRQQV80QUVBOVFFBSw8bUFLS2dQVFNES0FDQUxVQwUVBEwwCQhwT0FDQU9nQ0FQZ0NBSUFEQVEuLpoCJSFlQWwtYkE20ADwpndlQW5JQVFvaW9EMDBndy7YAugH4ALH0wHqAh9odHRwOi8vcHJlYmlkLm9yZzo5OTk5L2dwdC5odG1sgAMAiAMBkAMAmAMFoAMBqgMAsAMAuAMAwAOsAsgDANgDAOADAOgDAPgDA4AEAJIEBC9qcHSYBACiBAoxMC4xLjEzLjM3qASL7AmyBAgIABAAGAAgALgEAMAEAMgEANIECzEwLjAuOTMuMjAy&s=1fd8d5650fa1fb8d918a2f403d6a1f97c10d7ec2&referrer=http%3A%2F%2Fprebid.org%3A9999%2Fgpt.html', + 'responseTimestamp': 1462919239343, + 'requestTimestamp': 1462919238943, + 'bidder': 'pagescience', + 'adUnitCode': '/19968336/header-bid-tag-0', + 'timeToRespond': 400, + 'pbLg': '0.50', + 'pbMg': '0.50', + 'pbHg': '0.50', + 'pbAg': '0.50', + 'size': '300x250', + 'requestId': 123456, + 'adserverTargeting': { + 'hb_bidder': 'pagescience', + 'hb_adid': '25bedd4813632d7', + 'hb_pb': '10.00', + 'hb_size': '300x250', + 'foobar': '300x250' } }, { - "bidderCode": "brightcom", - "width": 300, - "height": 250, - "statusMessage": "Bid available", - "adId": "26e0795ab963896", - "cpm": 0.17, - "ad": "", - "responseTimestamp": 1462919239420, - "requestTimestamp": 1462919238937, - "bidder": "brightcom", - "adUnitCode": "/19968336/header-bid-tag-0", - "timeToRespond": 483, - "pbLg": "0.00", - "pbMg": "0.10", - "pbHg": "0.17", - "pbAg": "0.15", - "size": "300x250", - "requestId": 654321, - "adserverTargeting": { - "hb_bidder": "brightcom", - "hb_adid": "26e0795ab963896", - "hb_pb": "10.00", - "hb_size": "300x250", - "foobar": "300x250" + 'bidderCode': 'brightcom', + 'width': 300, + 'height': 250, + 'statusMessage': 'Bid available', + 'adId': '26e0795ab963896', + 'cpm': 0.17, + 'ad': "", + 'responseTimestamp': 1462919239420, + 'requestTimestamp': 1462919238937, + 'bidder': 'brightcom', + 'adUnitCode': '/19968336/header-bid-tag-0', + 'timeToRespond': 483, + 'pbLg': '0.00', + 'pbMg': '0.10', + 'pbHg': '0.17', + 'pbAg': '0.15', + 'size': '300x250', + 'requestId': 654321, + 'adserverTargeting': { + 'hb_bidder': 'brightcom', + 'hb_adid': '26e0795ab963896', + 'hb_pb': '10.00', + 'hb_size': '300x250', + 'foobar': '300x250' } }, { - "bidderCode": "brealtime", - "width": 300, - "height": 250, - "statusMessage": "Bid available", - "adId": "275bd666f5a5a5d", - "creative_id": 29681110, - "cpm": 0.5, - "adUrl": "http://lax1-ib.adnxs.com/ab?e=wqT_3QLzBKhzAgAAAwDWAAUBCMjAybkFEIPr4YfMvKLoQBjL84KE1tzG-kkgASotCQAAAQII4D8RAQcQAADgPxkJCQjwPyEJCQjgPykRCaAwuvekAji-B0C-B0gCUNbLkw5YweAnYABokUB4mo8EgAEBigEDVVNEkgUG8FKYAawCoAH6AagBAbABALgBAcABA8gBANABANgBAOABAPABAIoCOnVmKCdhJywgNDk0NDcyLCAxNDYyOTE5MjQwKTt1ZigncicsIDI5NjgxMTEwLDIeAPBvkgLNASFsU2NQWlFpNjBJY0VFTmJMa3c0WUFDREI0Q2N3QURnQVFBUkl2Z2RRdXZla0FsZ0FZSk1IYUFCdzNBMTRDb0FCcGh5SUFRcVFBUUdZQVFHZ0FRR29BUU93QVFDNUFRQUFBQUFBQU9BX3dRRQkMSEFEZ1A4a0JHZmNvazFBejFUX1oVKCRQQV80QUVBOVFFBSw8bUFLS2dOU0NEYUFDQUxVQwUVBEwwCQh0T0FDQU9nQ0FQZ0NBSUFEQVEuLpoCJSFDUWxfYXdpMtAA8KZ3ZUFuSUFRb2lvRFVnZzAu2ALoB-ACx9MB6gIfaHR0cDovL3ByZWJpZC5vcmc6OTk5OS9ncHQuaHRtbIADAIgDAZADAJgDBaADAaoDALADALgDAMADrALIAwDYAwDgAwDoAwD4AwOABACSBAQvanB0mAQAogQKMTAuMS4xMy4zN6gEi-wJsgQICAAQABgAIAC4BADABADIBADSBAsxMC4wLjg1LjIwOA..&s=975cfe6518f064683541240f0d780d93a5f973da&referrer=http%3A%2F%2Fprebid.org%3A9999%2Fgpt.html", - "responseTimestamp": 1462919239486, - "requestTimestamp": 1462919238941, - "bidder": "brealtime", - "adUnitCode": "/19968336/header-bid-tag-0", - "timeToRespond": 545, - "pbLg": "0.50", - "pbMg": "0.50", - "pbHg": "0.50", - "pbAg": "0.50", - "size": "300x250", - "requestId": 654321, - "adserverTargeting": { - "hb_bidder": "brealtime", - "hb_adid": "275bd666f5a5a5d", - "hb_pb": "10.00", - "hb_size": "300x250", - "foobar": "300x250" + 'bidderCode': 'brealtime', + 'width': 300, + 'height': 250, + 'statusMessage': 'Bid available', + 'adId': '275bd666f5a5a5d', + 'creative_id': 29681110, + 'cpm': 0.5, + 'adUrl': 'http://lax1-ib.adnxs.com/ab?e=wqT_3QLzBKhzAgAAAwDWAAUBCMjAybkFEIPr4YfMvKLoQBjL84KE1tzG-kkgASotCQAAAQII4D8RAQcQAADgPxkJCQjwPyEJCQjgPykRCaAwuvekAji-B0C-B0gCUNbLkw5YweAnYABokUB4mo8EgAEBigEDVVNEkgUG8FKYAawCoAH6AagBAbABALgBAcABA8gBANABANgBAOABAPABAIoCOnVmKCdhJywgNDk0NDcyLCAxNDYyOTE5MjQwKTt1ZigncicsIDI5NjgxMTEwLDIeAPBvkgLNASFsU2NQWlFpNjBJY0VFTmJMa3c0WUFDREI0Q2N3QURnQVFBUkl2Z2RRdXZla0FsZ0FZSk1IYUFCdzNBMTRDb0FCcGh5SUFRcVFBUUdZQVFHZ0FRR29BUU93QVFDNUFRQUFBQUFBQU9BX3dRRQkMSEFEZ1A4a0JHZmNvazFBejFUX1oVKCRQQV80QUVBOVFFBSw8bUFLS2dOU0NEYUFDQUxVQwUVBEwwCQh0T0FDQU9nQ0FQZ0NBSUFEQVEuLpoCJSFDUWxfYXdpMtAA8KZ3ZUFuSUFRb2lvRFVnZzAu2ALoB-ACx9MB6gIfaHR0cDovL3ByZWJpZC5vcmc6OTk5OS9ncHQuaHRtbIADAIgDAZADAJgDBaADAaoDALADALgDAMADrALIAwDYAwDgAwDoAwD4AwOABACSBAQvanB0mAQAogQKMTAuMS4xMy4zN6gEi-wJsgQICAAQABgAIAC4BADABADIBADSBAsxMC4wLjg1LjIwOA..&s=975cfe6518f064683541240f0d780d93a5f973da&referrer=http%3A%2F%2Fprebid.org%3A9999%2Fgpt.html', + 'responseTimestamp': 1462919239486, + 'requestTimestamp': 1462919238941, + 'bidder': 'brealtime', + 'adUnitCode': '/19968336/header-bid-tag-0', + 'timeToRespond': 545, + 'pbLg': '0.50', + 'pbMg': '0.50', + 'pbHg': '0.50', + 'pbAg': '0.50', + 'size': '300x250', + 'requestId': 654321, + 'adserverTargeting': { + 'hb_bidder': 'brealtime', + 'hb_adid': '275bd666f5a5a5d', + 'hb_pb': '10.00', + 'hb_size': '300x250', + 'foobar': '300x250' } }, { - "bidderCode": "pubmatic", - "width": "300", - "height": "250", - "statusMessage": "Bid available", - "adId": "28f4039c636b6a7", - "adSlot": "39620189@300x250", - "cpm": 5.9396, - "ad": "\r
", - "dealId": "", - "responseTimestamp": 1462919239544, - "requestTimestamp": 1462919238922, - "bidder": "pubmatic", - "adUnitCode": "/19968336/header-bid-tag-0", - "timeToRespond": 622, - "pbLg": "5.00", - "pbMg": "5.90", - "pbHg": "5.93", - "pbAg": "5.90", - "size": "300x250", - "requestId": 654321, - "adserverTargeting": { - "hb_bidder": "pubmatic", - "hb_adid": "28f4039c636b6a7", - "hb_pb": "10.00", - "hb_size": "300x250", - "foobar": "300x250" + 'bidderCode': 'pubmatic', + 'width': '300', + 'height': '250', + 'statusMessage': 'Bid available', + 'adId': '28f4039c636b6a7', + 'adSlot': '39620189@300x250', + 'cpm': 5.9396, + 'ad': "\r
", + 'dealId': '', + 'responseTimestamp': 1462919239544, + 'requestTimestamp': 1462919238922, + 'bidder': 'pubmatic', + 'adUnitCode': '/19968336/header-bid-tag-0', + 'timeToRespond': 622, + 'pbLg': '5.00', + 'pbMg': '5.90', + 'pbHg': '5.93', + 'pbAg': '5.90', + 'size': '300x250', + 'requestId': 654321, + 'adserverTargeting': { + 'hb_bidder': 'pubmatic', + 'hb_adid': '28f4039c636b6a7', + 'hb_pb': '10.00', + 'hb_size': '300x250', + 'foobar': '300x250' } }, { - "bidderCode": "rubicon", - "width": 300, - "height": 600, - "statusMessage": "Bid available", - "adId": "29019e2ab586a5a", - "cpm": 2.74, - "ad": "", - "responseTimestamp": 1462919239860, - "requestTimestamp": 1462919238934, - "bidder": "rubicon", - "adUnitCode": "/19968336/header-bid-tag-0", - "timeToRespond": 926, - "pbLg": "2.50", - "pbMg": "2.70", - "pbHg": "2.74", - "pbAg": "2.70", - "size": "300x600", - "requestId": 654321, - "adserverTargeting": { - "hb_bidder": "rubicon", - "hb_adid": "29019e2ab586a5a", - "hb_pb": "10.00", - "hb_size": "300x600", - "foobar": "300x600" + 'bidderCode': 'rubicon', + 'width': 300, + 'height': 600, + 'statusMessage': 'Bid available', + 'adId': '29019e2ab586a5a', + 'cpm': 2.74, + 'ad': '', + 'responseTimestamp': 1462919239860, + 'requestTimestamp': 1462919238934, + 'bidder': 'rubicon', + 'adUnitCode': '/19968336/header-bid-tag-0', + 'timeToRespond': 926, + 'pbLg': '2.50', + 'pbMg': '2.70', + 'pbHg': '2.74', + 'pbAg': '2.70', + 'size': '300x600', + 'requestId': 654321, + 'adserverTargeting': { + 'hb_bidder': 'rubicon', + 'hb_adid': '29019e2ab586a5a', + 'hb_pb': '10.00', + 'hb_size': '300x600', + 'foobar': '300x600' } } ]; @@ -521,30 +521,30 @@ export function getBidResponses() { export function getSlotTargeting() { return { - "/19968336/header-bid-tag-0": [ + '/19968336/header-bid-tag-0': [ { - "hb_bidder": [ - "appnexus" + 'hb_bidder': [ + 'appnexus' ] }, { - "hb_adid": [ - "233bcbee889d46d" + 'hb_adid': [ + '233bcbee889d46d' ] }, { - "hb_pb": [ - "10.00" + 'hb_pb': [ + '10.00' ] }, { - "hb_size": [ - "300x250" + 'hb_size': [ + '300x250' ] }, { - "foobar": [ - "300x250" + 'foobar': [ + '300x250' ] } ] @@ -554,8 +554,8 @@ export function getSlotTargeting() { export function getAdUnits() { return [ { - "code": "/19968336/header-bid-tag1", - "sizes": [ + 'code': '/19968336/header-bid-tag1', + 'sizes': [ [ 728, 90 @@ -565,15 +565,15 @@ export function getAdUnits() { 90 ] ], - "bids": [ + 'bids': [ { - "bidder": "adequant", - "params": { - "publisher_id": "1234567", - "bidfloor": 0.01 + 'bidder': 'adequant', + 'params': { + 'publisher_id': '1234567', + 'bidfloor': 0.01 }, - "placementCode": "/19968336/header-bid-tag1", - "sizes": [ + 'placementCode': '/19968336/header-bid-tag1', + 'sizes': [ [ 728, 90 @@ -583,18 +583,18 @@ export function getAdUnits() { 90 ] ], - "bidId": "3692954f816efc", - "bidderRequestId": "2b1a75d5e826c4", - "requestId": "1ff753bd4ae5cb" + 'bidId': '3692954f816efc', + 'bidderRequestId': '2b1a75d5e826c4', + 'requestId': '1ff753bd4ae5cb' }, { - "bidder": "appnexus", - "params": { - "placementId": "543221", - "test": "me" + 'bidder': 'appnexus', + 'params': { + 'placementId': '543221', + 'test': 'me' }, - "placementCode": "/19968336/header-bid-tag1", - "sizes": [ + 'placementCode': '/19968336/header-bid-tag1', + 'sizes': [ [ 728, 90 @@ -604,17 +604,17 @@ export function getAdUnits() { 90 ] ], - "bidId": "68136e1c47023d", - "bidderRequestId": "55e24a66bed717", - "requestId": "1ff753bd4ae5cb", - "startTime": 1463510220995, - "status": 1 + 'bidId': '68136e1c47023d', + 'bidderRequestId': '55e24a66bed717', + 'requestId': '1ff753bd4ae5cb', + 'startTime': 1463510220995, + 'status': 1 } ] }, { - "code": "/19968336/header-bid-tag-0", - "sizes": [ + 'code': '/19968336/header-bid-tag-0', + 'sizes': [ [ 300, 250 @@ -624,14 +624,14 @@ export function getAdUnits() { 600 ] ], - "bids": [ + 'bids': [ { - "bidder": "appnexus", - "params": { - "placementId": "5324321" + 'bidder': 'appnexus', + 'params': { + 'placementId': '5324321' }, - "placementCode": "/19968336/header-bid-tag-0", - "sizes": [ + 'placementCode': '/19968336/header-bid-tag-0', + 'sizes': [ [ 300, 250 @@ -641,19 +641,19 @@ export function getAdUnits() { 600 ] ], - "bidId": "7e5d6af25ed188", - "bidderRequestId": "55e24a66bed717", - "requestId": "1ff753bd4ae5cb", - "startTime": 1463510220996 + 'bidId': '7e5d6af25ed188', + 'bidderRequestId': '55e24a66bed717', + 'requestId': '1ff753bd4ae5cb', + 'startTime': 1463510220996 }, { - "bidder": "adequant", - "params": { - "publisher_id": "12353433", - "bidfloor": 0.01 + 'bidder': 'adequant', + 'params': { + 'publisher_id': '12353433', + 'bidfloor': 0.01 }, - "placementCode": "/19968336/header-bid-tag-0", - "sizes": [ + 'placementCode': '/19968336/header-bid-tag-0', + 'sizes': [ [ 300, 250 @@ -663,17 +663,17 @@ export function getAdUnits() { 600 ] ], - "bidId": "4448d80ac1374e", - "bidderRequestId": "2b1a75d5e826c4", - "requestId": "1ff753bd4ae5cb" + 'bidId': '4448d80ac1374e', + 'bidderRequestId': '2b1a75d5e826c4', + 'requestId': '1ff753bd4ae5cb' }, { - "bidder": "triplelift", - "params": { - "inventoryCode": "inv_code_here" + 'bidder': 'triplelift', + 'params': { + 'inventoryCode': 'inv_code_here' }, - "placementCode": "/19968336/header-bid-tag-0", - "sizes": [ + 'placementCode': '/19968336/header-bid-tag-0', + 'sizes': [ [ 300, 250 @@ -683,20 +683,20 @@ export function getAdUnits() { 600 ] ], - "bidId": "9514d586c52abf", - "bidderRequestId": "8c4f03b838d7ee", - "requestId": "1ff753bd4ae5cb", - "startTime": 1463510220997 + 'bidId': '9514d586c52abf', + 'bidderRequestId': '8c4f03b838d7ee', + 'requestId': '1ff753bd4ae5cb', + 'startTime': 1463510220997 }, { - "bidder": "springserve", - "params": { - "impId": 1234, - "supplyPartnerId": 1, - "test": true + 'bidder': 'springserve', + 'params': { + 'impId': 1234, + 'supplyPartnerId': 1, + 'test': true }, - "placementCode": "/19968336/header-bid-tag-0", - "sizes": [ + 'placementCode': '/19968336/header-bid-tag-0', + 'sizes': [ [ 300, 250 @@ -706,37 +706,37 @@ export function getAdUnits() { 600 ] ], - "bidId": "113079fed03f58c", - "bidderRequestId": "1048e0df882e965", - "requestId": "1ff753bd4ae5cb" + 'bidId': '113079fed03f58c', + 'bidderRequestId': '1048e0df882e965', + 'requestId': '1ff753bd4ae5cb' }, { - "bidder": "rubicon", - "params": { - "accountId": "123456", - "siteId": "345678", - "zoneId": "234567", - "userId": "12346", - "keywords": [ - "a", - "b", - "c" + 'bidder': 'rubicon', + 'params': { + 'accountId': '123456', + 'siteId': '345678', + 'zoneId': '234567', + 'userId': '12346', + 'keywords': [ + 'a', + 'b', + 'c' ], - "inventory": { - "rating": "5-star", - "prodtype": "tech" + 'inventory': { + 'rating': '5-star', + 'prodtype': 'tech' }, - "visitor": { - "ucat": "new", - "search": "iphone" + 'visitor': { + 'ucat': 'new', + 'search': 'iphone' }, - "sizes": [ + 'sizes': [ 15, 10 ] }, - "placementCode": "/19968336/header-bid-tag-0", - "sizes": [ + 'placementCode': '/19968336/header-bid-tag-0', + 'sizes': [ [ 300, 250 @@ -746,18 +746,18 @@ export function getAdUnits() { 600 ] ], - "bidId": "13c2c2a79d155ea", - "bidderRequestId": "129e383ac549e5d", - "requestId": "1ff753bd4ae5cb" + 'bidId': '13c2c2a79d155ea', + 'bidderRequestId': '129e383ac549e5d', + 'requestId': '1ff753bd4ae5cb' }, { - "bidder": "openx", - "params": { - "jstag_url": "http://servedbyopenx.com/w/1.0/jstag?nc=account_key", - "unit": 2345677 + 'bidder': 'openx', + 'params': { + 'jstag_url': 'http://servedbyopenx.com/w/1.0/jstag?nc=account_key', + 'unit': 2345677 }, - "placementCode": "/19968336/header-bid-tag-0", - "sizes": [ + 'placementCode': '/19968336/header-bid-tag-0', + 'sizes': [ [ 300, 250 @@ -767,18 +767,18 @@ export function getAdUnits() { 600 ] ], - "bidId": "154f9cbf82df565", - "bidderRequestId": "1448569c2453b84", - "requestId": "1ff753bd4ae5cb" + 'bidId': '154f9cbf82df565', + 'bidderRequestId': '1448569c2453b84', + 'requestId': '1ff753bd4ae5cb' }, { - "bidder": "pubmatic", - "params": { - "publisherId": 1234567, - "adSlot": "1234567@300x250" + 'bidder': 'pubmatic', + 'params': { + 'publisherId': 1234567, + 'adSlot': '1234567@300x250' }, - "placementCode": "/19968336/header-bid-tag-0", - "sizes": [ + 'placementCode': '/19968336/header-bid-tag-0', + 'sizes': [ [ 300, 250 @@ -788,17 +788,17 @@ export function getAdUnits() { 600 ] ], - "bidId": "17f8c3a8fb13308", - "bidderRequestId": "16095445eeb05e4", - "requestId": "1ff753bd4ae5cb" + 'bidId': '17f8c3a8fb13308', + 'bidderRequestId': '16095445eeb05e4', + 'requestId': '1ff753bd4ae5cb' }, { - "bidder": "pagescience", - "params": { - "placementId": "1234567" + 'bidder': 'pagescience', + 'params': { + 'placementId': '1234567' }, - "placementCode": "/19968336/header-bid-tag-0", - "sizes": [ + 'placementCode': '/19968336/header-bid-tag-0', + 'sizes': [ [ 300, 250 @@ -808,18 +808,18 @@ export function getAdUnits() { 600 ] ], - "bidId": "2074d5757675542", - "bidderRequestId": "19883380ef5453a", - "requestId": "1ff753bd4ae5cb", - "startTime": 1463510221014 + 'bidId': '2074d5757675542', + 'bidderRequestId': '19883380ef5453a', + 'requestId': '1ff753bd4ae5cb', + 'startTime': 1463510221014 }, { - "bidder": "brealtime", - "params": { - "placementId": "1234567" + 'bidder': 'brealtime', + 'params': { + 'placementId': '1234567' }, - "placementCode": "/19968336/header-bid-tag-0", - "sizes": [ + 'placementCode': '/19968336/header-bid-tag-0', + 'sizes': [ [ 300, 250 @@ -829,20 +829,20 @@ export function getAdUnits() { 600 ] ], - "bidId": "222b6ad5a9b835d", - "bidderRequestId": "2163409fdf6f333", - "requestId": "1ff753bd4ae5cb", - "startTime": 1463510221015 + 'bidId': '222b6ad5a9b835d', + 'bidderRequestId': '2163409fdf6f333', + 'requestId': '1ff753bd4ae5cb', + 'startTime': 1463510221015 }, { - "bidder": "indexExchange", - "params": { - "id": "1", - "siteID": 123456, - "timeout": 10000 + 'bidder': 'indexExchange', + 'params': { + 'id': '1', + 'siteID': 123456, + 'timeout': 10000 }, - "placementCode": "/19968336/header-bid-tag-0", - "sizes": [ + 'placementCode': '/19968336/header-bid-tag-0', + 'sizes': [ [ 300, 250 @@ -852,19 +852,19 @@ export function getAdUnits() { 600 ] ], - "bidId": "2499961ab3f937a", - "bidderRequestId": "23b57a2de4ae50b", - "requestId": "1ff753bd4ae5cb" + 'bidId': '2499961ab3f937a', + 'bidderRequestId': '23b57a2de4ae50b', + 'requestId': '1ff753bd4ae5cb' }, { - "bidder": "adform", - "params": { - "adxDomain": "adx.adform.net", - "mid": 123456, - "test": 1 + 'bidder': 'adform', + 'params': { + 'adxDomain': 'adx.adform.net', + 'mid': 123456, + 'test': 1 }, - "placementCode": "/19968336/header-bid-tag-0", - "sizes": [ + 'placementCode': '/19968336/header-bid-tag-0', + 'sizes': [ [ 300, 250 @@ -874,17 +874,17 @@ export function getAdUnits() { 600 ] ], - "bidId": "26605265bf5e9c5", - "bidderRequestId": "25a0902299c17d3", - "requestId": "1ff753bd4ae5cb" + 'bidId': '26605265bf5e9c5', + 'bidderRequestId': '25a0902299c17d3', + 'requestId': '1ff753bd4ae5cb' }, { - "bidder": "amazon", - "params": { - "aId": 3080 + 'bidder': 'amazon', + 'params': { + 'aId': 3080 }, - "placementCode": "/19968336/header-bid-tag-0", - "sizes": [ + 'placementCode': '/19968336/header-bid-tag-0', + 'sizes': [ [ 300, 250 @@ -894,18 +894,18 @@ export function getAdUnits() { 600 ] ], - "bidId": "2935d8f6764fe45", - "bidderRequestId": "28afa21ca9246c1", - "requestId": "1ff753bd4ae5cb" + 'bidId': '2935d8f6764fe45', + 'bidderRequestId': '28afa21ca9246c1', + 'requestId': '1ff753bd4ae5cb' }, { - "bidder": "aol", - "params": { - "network": "112345.45", - "placement": 12345 + 'bidder': 'aol', + 'params': { + 'network': '112345.45', + 'placement': 12345 }, - "placementCode": "/19968336/header-bid-tag-0", - "sizes": [ + 'placementCode': '/19968336/header-bid-tag-0', + 'sizes': [ [ 300, 250 @@ -915,17 +915,17 @@ export function getAdUnits() { 600 ] ], - "bidId": "31d1489681dc539", - "bidderRequestId": "30bf32da9080fdd", - "requestId": "1ff753bd4ae5cb" + 'bidId': '31d1489681dc539', + 'bidderRequestId': '30bf32da9080fdd', + 'requestId': '1ff753bd4ae5cb' }, { - "bidder": "sovrn", - "params": { - "tagid": "123556" + 'bidder': 'sovrn', + 'params': { + 'tagid': '123556' }, - "placementCode": "/19968336/header-bid-tag-0", - "sizes": [ + 'placementCode': '/19968336/header-bid-tag-0', + 'sizes': [ [ 300, 250 @@ -935,19 +935,19 @@ export function getAdUnits() { 600 ] ], - "bidId": "33c1a8028d91563", - "bidderRequestId": "324bcb47cfcf034", - "requestId": "1ff753bd4ae5cb" + 'bidId': '33c1a8028d91563', + 'bidderRequestId': '324bcb47cfcf034', + 'requestId': '1ff753bd4ae5cb' }, { - "bidder": "pulsepoint", - "params": { - "cf": "300X250", - "cp": 1233456, - "ct": 12357 + 'bidder': 'pulsepoint', + 'params': { + 'cf': '300X250', + 'cp': 1233456, + 'ct': 12357 }, - "placementCode": "/19968336/header-bid-tag-0", - "sizes": [ + 'placementCode': '/19968336/header-bid-tag-0', + 'sizes': [ [ 300, 250 @@ -957,17 +957,17 @@ export function getAdUnits() { 600 ] ], - "bidId": "379219f0506a26f", - "bidderRequestId": "360ec66bbb0719c", - "requestId": "1ff753bd4ae5cb" + 'bidId': '379219f0506a26f', + 'bidderRequestId': '360ec66bbb0719c', + 'requestId': '1ff753bd4ae5cb' }, { - "bidder": "brightcom", - "params": { - "tagId": 75423 + 'bidder': 'brightcom', + 'params': { + 'tagId': 75423 }, - "placementCode": "/19968336/header-bid-tag-0", - "sizes": [ + 'placementCode': '/19968336/header-bid-tag-0', + 'sizes': [ [ 300, 250 @@ -977,9 +977,9 @@ export function getAdUnits() { 600 ] ], - "bidId": "395cfcf496e7d6d", - "bidderRequestId": "38a776c7f001ea", - "requestId": "1ff753bd4ae5cb" + 'bidId': '395cfcf496e7d6d', + 'bidderRequestId': '38a776c7f001ea', + 'requestId': '1ff753bd4ae5cb' } ] } @@ -988,117 +988,117 @@ export function getAdUnits() { export function getBidResponsesFromAPI() { return { - "/19968336/header-bid-tag-0": { - "bids": [ + '/19968336/header-bid-tag-0': { + 'bids': [ { - "bidderCode": "brightcom", - "width": 300, - "height": 250, - "statusMessage": "Bid available", - "adId": "26e0795ab963896", - "cpm": 0.17, - "ad": "", - "responseTimestamp": 1462919239420, - "requestTimestamp": 1462919238937, - "bidder": "brightcom", - "adUnitCode": "/19968336/header-bid-tag-0", - "timeToRespond": 483, - "pbLg": "0.00", - "pbMg": "0.10", - "pbHg": "0.17", - "pbAg": "0.15", - "size": "300x250", - "requestId": 654321, - "adserverTargeting": { - "hb_bidder": "brightcom", - "hb_adid": "26e0795ab963896", - "hb_pb": "10.00", - "hb_size": "300x250", - "foobar": "300x250" + 'bidderCode': 'brightcom', + 'width': 300, + 'height': 250, + 'statusMessage': 'Bid available', + 'adId': '26e0795ab963896', + 'cpm': 0.17, + 'ad': "", + 'responseTimestamp': 1462919239420, + 'requestTimestamp': 1462919238937, + 'bidder': 'brightcom', + 'adUnitCode': '/19968336/header-bid-tag-0', + 'timeToRespond': 483, + 'pbLg': '0.00', + 'pbMg': '0.10', + 'pbHg': '0.17', + 'pbAg': '0.15', + 'size': '300x250', + 'requestId': 654321, + 'adserverTargeting': { + 'hb_bidder': 'brightcom', + 'hb_adid': '26e0795ab963896', + 'hb_pb': '10.00', + 'hb_size': '300x250', + 'foobar': '300x250' } }, { - "bidderCode": "brealtime", - "width": 300, - "height": 250, - "statusMessage": "Bid available", - "adId": "275bd666f5a5a5d", - "creative_id": 29681110, - "cpm": 0.5, - "adUrl": "http://lax1-ib.adnxs.com/ab?e=wqT_3QLzBKhzAgAAAwDWAAUBCMjAybkFEIPr4YfMvKLoQBjL84KE1tzG-kkgASotCQAAAQII4D8RAQcQAADgPxkJCQjwPyEJCQjgPykRCaAwuvekAji-B0C-B0gCUNbLkw5YweAnYABokUB4mo8EgAEBigEDVVNEkgUG8FKYAawCoAH6AagBAbABALgBAcABA8gBANABANgBAOABAPABAIoCOnVmKCdhJywgNDk0NDcyLCAxNDYyOTE5MjQwKTt1ZigncicsIDI5NjgxMTEwLDIeAPBvkgLNASFsU2NQWlFpNjBJY0VFTmJMa3c0WUFDREI0Q2N3QURnQVFBUkl2Z2RRdXZla0FsZ0FZSk1IYUFCdzNBMTRDb0FCcGh5SUFRcVFBUUdZQVFHZ0FRR29BUU93QVFDNUFRQUFBQUFBQU9BX3dRRQkMSEFEZ1A4a0JHZmNvazFBejFUX1oVKCRQQV80QUVBOVFFBSw8bUFLS2dOU0NEYUFDQUxVQwUVBEwwCQh0T0FDQU9nQ0FQZ0NBSUFEQVEuLpoCJSFDUWxfYXdpMtAA8KZ3ZUFuSUFRb2lvRFVnZzAu2ALoB-ACx9MB6gIfaHR0cDovL3ByZWJpZC5vcmc6OTk5OS9ncHQuaHRtbIADAIgDAZADAJgDBaADAaoDALADALgDAMADrALIAwDYAwDgAwDoAwD4AwOABACSBAQvanB0mAQAogQKMTAuMS4xMy4zN6gEi-wJsgQICAAQABgAIAC4BADABADIBADSBAsxMC4wLjg1LjIwOA..&s=975cfe6518f064683541240f0d780d93a5f973da&referrer=http%3A%2F%2Fprebid.org%3A9999%2Fgpt.html", - "responseTimestamp": 1462919239486, - "requestTimestamp": 1462919238941, - "bidder": "brealtime", - "adUnitCode": "/19968336/header-bid-tag-0", - "timeToRespond": 545, - "pbLg": "0.50", - "pbMg": "0.50", - "pbHg": "0.50", - "pbAg": "0.50", - "size": "300x250", - "requestId": 654321, - "adserverTargeting": { - "hb_bidder": "brealtime", - "hb_adid": "275bd666f5a5a5d", - "hb_pb": "10.00", - "hb_size": "300x250", - "foobar": "300x250" + 'bidderCode': 'brealtime', + 'width': 300, + 'height': 250, + 'statusMessage': 'Bid available', + 'adId': '275bd666f5a5a5d', + 'creative_id': 29681110, + 'cpm': 0.5, + 'adUrl': 'http://lax1-ib.adnxs.com/ab?e=wqT_3QLzBKhzAgAAAwDWAAUBCMjAybkFEIPr4YfMvKLoQBjL84KE1tzG-kkgASotCQAAAQII4D8RAQcQAADgPxkJCQjwPyEJCQjgPykRCaAwuvekAji-B0C-B0gCUNbLkw5YweAnYABokUB4mo8EgAEBigEDVVNEkgUG8FKYAawCoAH6AagBAbABALgBAcABA8gBANABANgBAOABAPABAIoCOnVmKCdhJywgNDk0NDcyLCAxNDYyOTE5MjQwKTt1ZigncicsIDI5NjgxMTEwLDIeAPBvkgLNASFsU2NQWlFpNjBJY0VFTmJMa3c0WUFDREI0Q2N3QURnQVFBUkl2Z2RRdXZla0FsZ0FZSk1IYUFCdzNBMTRDb0FCcGh5SUFRcVFBUUdZQVFHZ0FRR29BUU93QVFDNUFRQUFBQUFBQU9BX3dRRQkMSEFEZ1A4a0JHZmNvazFBejFUX1oVKCRQQV80QUVBOVFFBSw8bUFLS2dOU0NEYUFDQUxVQwUVBEwwCQh0T0FDQU9nQ0FQZ0NBSUFEQVEuLpoCJSFDUWxfYXdpMtAA8KZ3ZUFuSUFRb2lvRFVnZzAu2ALoB-ACx9MB6gIfaHR0cDovL3ByZWJpZC5vcmc6OTk5OS9ncHQuaHRtbIADAIgDAZADAJgDBaADAaoDALADALgDAMADrALIAwDYAwDgAwDoAwD4AwOABACSBAQvanB0mAQAogQKMTAuMS4xMy4zN6gEi-wJsgQICAAQABgAIAC4BADABADIBADSBAsxMC4wLjg1LjIwOA..&s=975cfe6518f064683541240f0d780d93a5f973da&referrer=http%3A%2F%2Fprebid.org%3A9999%2Fgpt.html', + 'responseTimestamp': 1462919239486, + 'requestTimestamp': 1462919238941, + 'bidder': 'brealtime', + 'adUnitCode': '/19968336/header-bid-tag-0', + 'timeToRespond': 545, + 'pbLg': '0.50', + 'pbMg': '0.50', + 'pbHg': '0.50', + 'pbAg': '0.50', + 'size': '300x250', + 'requestId': 654321, + 'adserverTargeting': { + 'hb_bidder': 'brealtime', + 'hb_adid': '275bd666f5a5a5d', + 'hb_pb': '10.00', + 'hb_size': '300x250', + 'foobar': '300x250' } }, { - "bidderCode": "pubmatic", - "width": "300", - "height": "250", - "statusMessage": "Bid available", - "adId": "28f4039c636b6a7", - "adSlot": "39620189@300x250", - "cpm": 5.9396, - "ad": "\r
", - "dealId": "", - "responseTimestamp": 1462919239544, - "requestTimestamp": 1462919238922, - "bidder": "pubmatic", - "adUnitCode": "/19968336/header-bid-tag-0", - "timeToRespond": 622, - "pbLg": "5.00", - "pbMg": "5.90", - "pbHg": "5.93", - "pbAg": "5.90", - "size": "300x250", - "requestId": 654321, - "adserverTargeting": { - "hb_bidder": "pubmatic", - "hb_adid": "28f4039c636b6a7", - "hb_pb": "10.00", - "hb_size": "300x250", - "foobar": "300x250" + 'bidderCode': 'pubmatic', + 'width': '300', + 'height': '250', + 'statusMessage': 'Bid available', + 'adId': '28f4039c636b6a7', + 'adSlot': '39620189@300x250', + 'cpm': 5.9396, + 'ad': "\r
", + 'dealId': '', + 'responseTimestamp': 1462919239544, + 'requestTimestamp': 1462919238922, + 'bidder': 'pubmatic', + 'adUnitCode': '/19968336/header-bid-tag-0', + 'timeToRespond': 622, + 'pbLg': '5.00', + 'pbMg': '5.90', + 'pbHg': '5.93', + 'pbAg': '5.90', + 'size': '300x250', + 'requestId': 654321, + 'adserverTargeting': { + 'hb_bidder': 'pubmatic', + 'hb_adid': '28f4039c636b6a7', + 'hb_pb': '10.00', + 'hb_size': '300x250', + 'foobar': '300x250' } }, { - "bidderCode": "rubicon", - "width": 300, - "height": 600, - "statusMessage": "Bid available", - "adId": "29019e2ab586a5a", - "cpm": 2.74, - "ad": "", - "responseTimestamp": 1462919239860, - "requestTimestamp": 1462919238934, - "bidder": "rubicon", - "adUnitCode": "/19968336/header-bid-tag-0", - "timeToRespond": 926, - "pbLg": "2.50", - "pbMg": "2.70", - "pbHg": "2.74", - "pbAg": "2.70", - "size": "300x600", - "requestId": 654321, - "adserverTargeting": { - "hb_bidder": "rubicon", - "hb_adid": "29019e2ab586a5a", - "hb_pb": "10.00", - "hb_size": "300x600", - "foobar": "300x600" + 'bidderCode': 'rubicon', + 'width': 300, + 'height': 600, + 'statusMessage': 'Bid available', + 'adId': '29019e2ab586a5a', + 'cpm': 2.74, + 'ad': '', + 'responseTimestamp': 1462919239860, + 'requestTimestamp': 1462919238934, + 'bidder': 'rubicon', + 'adUnitCode': '/19968336/header-bid-tag-0', + 'timeToRespond': 926, + 'pbLg': '2.50', + 'pbMg': '2.70', + 'pbHg': '2.74', + 'pbAg': '2.70', + 'size': '300x600', + 'requestId': 654321, + 'adserverTargeting': { + 'hb_bidder': 'rubicon', + 'hb_adid': '29019e2ab586a5a', + 'hb_pb': '10.00', + 'hb_size': '300x600', + 'foobar': '300x600' } } ] @@ -1109,51 +1109,51 @@ export function getBidResponsesFromAPI() { // Ad server targeting when `$$PREBID_GLOBAL$$.enableSendAllBids()` is called. export function getAdServerTargeting() { return { - "/19968336/header-bid-tag-0": { - "foobar": "300x250", - "hb_size": "300x250", - "hb_pb": "10.00", - "hb_adid": "233bcbee889d46d", - "hb_bidder": "appnexus", - "hb_size_triplelift": "0x0", - "hb_pb_triplelift": "10.00", - "hb_adid_triplelift": "222bb26f9e8bd", - "hb_bidder_triplelift": "triplelift", - "hb_size_appnexus": "300x250", - "hb_pb_appnexus": "10.00", - "hb_adid_appnexus": "233bcbee889d46d", - "hb_bidder_appnexus": "appnexus", - "hb_size_pagescience": "300x250", - "hb_pb_pagescience": "10.00", - "hb_adid_pagescience": "25bedd4813632d7", - "hb_bidder_pagescienc": "pagescience", - "hb_size_brightcom": "300x250", - "hb_pb_brightcom": "10.00", - "hb_adid_brightcom": "26e0795ab963896", - "hb_bidder_brightcom": "brightcom", - "hb_size_brealtime": "300x250", - "hb_pb_brealtime": "10.00", - "hb_adid_brealtime": "275bd666f5a5a5d", - "hb_bidder_brealtime": "brealtime", - "hb_size_pubmatic": "300x250", - "hb_pb_pubmatic": "10.00", - "hb_adid_pubmatic": "28f4039c636b6a7", - "hb_bidder_pubmatic": "pubmatic", - "hb_size_rubicon": "300x600", - "hb_pb_rubicon": "10.00", - "hb_adid_rubicon": "29019e2ab586a5a", - "hb_bidder_rubicon": "rubicon" + '/19968336/header-bid-tag-0': { + 'foobar': '300x250', + 'hb_size': '300x250', + 'hb_pb': '10.00', + 'hb_adid': '233bcbee889d46d', + 'hb_bidder': 'appnexus', + 'hb_size_triplelift': '0x0', + 'hb_pb_triplelift': '10.00', + 'hb_adid_triplelift': '222bb26f9e8bd', + 'hb_bidder_triplelift': 'triplelift', + 'hb_size_appnexus': '300x250', + 'hb_pb_appnexus': '10.00', + 'hb_adid_appnexus': '233bcbee889d46d', + 'hb_bidder_appnexus': 'appnexus', + 'hb_size_pagescience': '300x250', + 'hb_pb_pagescience': '10.00', + 'hb_adid_pagescience': '25bedd4813632d7', + 'hb_bidder_pagescienc': 'pagescience', + 'hb_size_brightcom': '300x250', + 'hb_pb_brightcom': '10.00', + 'hb_adid_brightcom': '26e0795ab963896', + 'hb_bidder_brightcom': 'brightcom', + 'hb_size_brealtime': '300x250', + 'hb_pb_brealtime': '10.00', + 'hb_adid_brealtime': '275bd666f5a5a5d', + 'hb_bidder_brealtime': 'brealtime', + 'hb_size_pubmatic': '300x250', + 'hb_pb_pubmatic': '10.00', + 'hb_adid_pubmatic': '28f4039c636b6a7', + 'hb_bidder_pubmatic': 'pubmatic', + 'hb_size_rubicon': '300x600', + 'hb_pb_rubicon': '10.00', + 'hb_adid_rubicon': '29019e2ab586a5a', + 'hb_bidder_rubicon': 'rubicon' }, - "/19968336/header-bid-tag1": { - "foobar": "728x90", - "hb_size": "728x90", - "hb_pb": "10.00", - "hb_adid": "24bd938435ec3fc", - "hb_bidder": "appnexus", - "hb_size_appnexus": "728x90", - "hb_pb_appnexus": "10.00", - "hb_adid_appnexus": "24bd938435ec3fc", - "hb_bidder_appnexus": "appnexus" + '/19968336/header-bid-tag1': { + 'foobar': '728x90', + 'hb_size': '728x90', + 'hb_pb': '10.00', + 'hb_adid': '24bd938435ec3fc', + 'hb_bidder': 'appnexus', + 'hb_size_appnexus': '728x90', + 'hb_pb_appnexus': '10.00', + 'hb_adid_appnexus': '24bd938435ec3fc', + 'hb_bidder_appnexus': 'appnexus' } }; } @@ -1162,28 +1162,28 @@ export function getAdServerTargeting() { export function getTargetingKeys() { return [ [ - "hb_bidder", - "appnexus" + 'hb_bidder', + 'appnexus' ], [ - "hb_adid", - "233bcbee889d46d" + 'hb_adid', + '233bcbee889d46d' ], [ - "hb_pb", - "10.00" + 'hb_pb', + '10.00' ], [ - "hb_size", - "300x250" + 'hb_size', + '300x250' ], [ - "foobar", - "300x250" + 'foobar', + '300x250' ], [ - "foobar", - "300x250" + 'foobar', + '300x250' ] ]; } @@ -1193,158 +1193,158 @@ export function getTargetingKeys() { export function getTargetingKeysBidLandscape() { return [ [ - "hb_bidder", - "appnexus" + 'hb_bidder', + 'appnexus' ], [ - "hb_adid", - "233bcbee889d46d" + 'hb_adid', + '233bcbee889d46d' ], [ - "hb_pb", - "10.00" + 'hb_pb', + '10.00' ], [ - "hb_size", - "300x250" + 'hb_size', + '300x250' ], [ - "foobar", - "300x250" + 'foobar', + '300x250' ], [ - "foobar", - "300x250" + 'foobar', + '300x250' ], [ - "hb_bidder_triplelift", - "triplelift" + 'hb_bidder_triplelift', + 'triplelift' ], [ - "hb_adid_triplelift", - "222bb26f9e8bd" + 'hb_adid_triplelift', + '222bb26f9e8bd' ], [ - "hb_pb_triplelift", - "10.00" + 'hb_pb_triplelift', + '10.00' ], [ - "hb_size_triplelift", - "0x0" + 'hb_size_triplelift', + '0x0' ], [ - "hb_bidder_appnexus", - "appnexus" + 'hb_bidder_appnexus', + 'appnexus' ], [ - "hb_adid_appnexus", - "233bcbee889d46d" + 'hb_adid_appnexus', + '233bcbee889d46d' ], [ - "hb_pb_appnexus", - "10.00" + 'hb_pb_appnexus', + '10.00' ], [ - "hb_size_appnexus", - "300x250" + 'hb_size_appnexus', + '300x250' ], [ - "hb_bidder_pagescienc", - "pagescience" + 'hb_bidder_pagescienc', + 'pagescience' ], [ - "hb_adid_pagescience", - "25bedd4813632d7" + 'hb_adid_pagescience', + '25bedd4813632d7' ], [ - "hb_pb_pagescience", - "10.00" + 'hb_pb_pagescience', + '10.00' ], [ - "hb_size_pagescience", - "300x250" + 'hb_size_pagescience', + '300x250' ], [ - "hb_bidder_brightcom", - "brightcom" + 'hb_bidder_brightcom', + 'brightcom' ], [ - "hb_adid_brightcom", - "26e0795ab963896" + 'hb_adid_brightcom', + '26e0795ab963896' ], [ - "hb_pb_brightcom", - "10.00" + 'hb_pb_brightcom', + '10.00' ], [ - "hb_size_brightcom", - "300x250" + 'hb_size_brightcom', + '300x250' ], [ - "hb_bidder_brealtime", - "brealtime" + 'hb_bidder_brealtime', + 'brealtime' ], [ - "hb_adid_brealtime", - "275bd666f5a5a5d" + 'hb_adid_brealtime', + '275bd666f5a5a5d' ], [ - "hb_pb_brealtime", - "10.00" + 'hb_pb_brealtime', + '10.00' ], [ - "hb_size_brealtime", - "300x250" + 'hb_size_brealtime', + '300x250' ], [ - "hb_bidder_pubmatic", - "pubmatic" + 'hb_bidder_pubmatic', + 'pubmatic' ], [ - "hb_adid_pubmatic", - "28f4039c636b6a7" + 'hb_adid_pubmatic', + '28f4039c636b6a7' ], [ - "hb_pb_pubmatic", - "10.00" + 'hb_pb_pubmatic', + '10.00' ], [ - "hb_size_pubmatic", - "300x250" + 'hb_size_pubmatic', + '300x250' ], [ - "hb_bidder_rubicon", - "rubicon" + 'hb_bidder_rubicon', + 'rubicon' ], [ - "hb_adid_rubicon", - "29019e2ab586a5a" + 'hb_adid_rubicon', + '29019e2ab586a5a' ], [ - "hb_pb_rubicon", - "10.00" + 'hb_pb_rubicon', + '10.00' ], [ - "hb_size_rubicon", - "300x600" + 'hb_size_rubicon', + '300x600' ] ]; } export function getBidRequestedPayload() { return { - "bidderCode": "adequant", - "requestId": "150f361b202aa8", - "bidderRequestId": "2b193b7a6ff421", - "bids": [ + 'bidderCode': 'adequant', + 'requestId': '150f361b202aa8', + 'bidderRequestId': '2b193b7a6ff421', + 'bids': [ { - "bidder": "adequant", - "params": { - "publisher_id": "5000563", - "bidfloor": 0.01 + 'bidder': 'adequant', + 'params': { + 'publisher_id': '5000563', + 'bidfloor': 0.01 }, - "placementCode": "/19968336/header-bid-tag-1", - "sizes": [ + 'placementCode': '/19968336/header-bid-tag-1', + 'sizes': [ [ 300, 250 @@ -1362,11 +1362,11 @@ export function getBidRequestedPayload() { 100 ] ], - "bidId": "39032dc5c7e834", - "bidderRequestId": "2b193b7a6ff421", - "requestId": "150f361b202aa8" + 'bidId': '39032dc5c7e834', + 'bidderRequestId': '2b193b7a6ff421', + 'requestId': '150f361b202aa8' } ], - "start": 1465426155412 + 'start': 1465426155412 }; } diff --git a/test/fixtures/video/adUnit.json b/test/fixtures/video/adUnit.json new file mode 100644 index 00000000000..6d2b7c385ad --- /dev/null +++ b/test/fixtures/video/adUnit.json @@ -0,0 +1,17 @@ +{ + "code": "video1", + "sizes": [640,480], + "mediaType": "video", + "bids": [ + { + "bidder": "appnexusAst", + "params": { + "placementId": "9333431", + "video": { + "skipppable": false, + "playback_methods": ["auto_play_sound_off"] + } + } + } + ] +} diff --git a/test/fixtures/video/bidRequest.json b/test/fixtures/video/bidRequest.json new file mode 100644 index 00000000000..75f054611c4 --- /dev/null +++ b/test/fixtures/video/bidRequest.json @@ -0,0 +1,26 @@ +{ + "auctionStart": 1462918897459, + "bidderCode": "appnexusAst", + "bidderRequestId": "2946b569352ef2", + "bids": [ + { + "bidder": "appnexusAst", + "params": { + "placementId": "9333431", + "video": { + "skipppable": false, + "playback_methods": ["auto_play_sound_off"] + } + }, + "placementCode": "video1", + "sizes": [640,480], + "bidId": "392b5a6b05d648", + "bidderRequestId": "2946b569352ef2", + "requestId": "6172477f-987f-4523-a967-fa6d7a434ddf", + "startTime": 1462918897462 + } + ], + "requestId": "6172477f-987f-4523-a967-fa6d7a434ddf", + "start": 1462918897460, + "timeout": 5000 +} diff --git a/test/fixtures/video/bidResponse.json b/test/fixtures/video/bidResponse.json new file mode 100644 index 00000000000..cba0798251d --- /dev/null +++ b/test/fixtures/video/bidResponse.json @@ -0,0 +1,13 @@ +{ + "adUnitCode": "video1", + "bidder": "appnexusAst", + "bidderCode": "appnexusAst", + "code": "appnexusAst", + "dealId": "foo", + "cpm": 0.1, + "height": 480, + "mediaType": "video", + "requestId": "6172477f-987f-4523-a967-fa6d7a434ddf", + "vastUrl": "www.myVastUrl.com", + "width": 640 +} diff --git a/test/helpers/index_adapter_utils.js b/test/helpers/index_adapter_utils.js index ab96743e960..716ec1ff4f3 100644 --- a/test/helpers/index_adapter_utils.js +++ b/test/helpers/index_adapter_utils.js @@ -1,328 +1,324 @@ var AllowedAdUnits = [[728, 90], [120, 600], [300, 250], [160, 600], [336, 280], [234, 60], [300, 600], [300, 50], [320, 50], [970, 250], [300, 1050], [970, 90], [180, 150]]; var UnsupportedAdUnits = [[700, 100], [100, 600], [300, 200], [100, 600], [300, 200], [200, 60], [900, 200], [300, 1000], [900, 90], [100, 100]]; -exports.supportedSizes = AllowedAdUnits; +exports.supportedSizes = AllowedAdUnits; exports.unsupportedSizes = UnsupportedAdUnits; -var DefaultSiteID = 234567; -var DefaultPlacementCodePrefix = "placementCode-"; -var DefaultCurrency = 'USD'; -var DefaultDspID = 124; -var DefaultTradingDeskID = 3456; -var DefaultCreativeID = 123234; -var DefaultBrandID = 123356; -var DefaultBrand = "LA Tourism & Convention Board"; -var DefaultAdDoman = 2342342; -var DefaultPriceLevel = 1000; //only this is important? -var DefaultDeal = '515'; -var DefaultDealName = 'name: testdeal'; -var DefaultDealID = 'ixdl'; - -var ADAPTER_CODE = 'indexExchange'; - -exports.DefaultSiteID = DefaultSiteID; -exports.DefaultPlacementCodePrefix = DefaultPlacementCodePrefix; -exports.DefaultCurrency = DefaultCurrency; -exports.DefaultDspID = DefaultDspID; -exports.DefaultTradingDeskID = DefaultTradingDeskID; -exports.DefaultCreativeID = DefaultCreativeID; -exports.DefaultBrandID = DefaultBrandID; -exports.DefaultBrand = DefaultBrand; -exports.DefaultAdDoman = DefaultAdDoman; -exports.DefaultPriceLevel = DefaultPriceLevel; -exports.DefaultDeal = DefaultDeal; -exports.DefaultDealName = DefaultDealName; -exports.DefaultDealID = DefaultDealID; - -exports.ADAPTER_CODE = ADAPTER_CODE; +var DefaultSiteID = 234567; +var DefaultPlacementCodePrefix = 'placementCode-'; +var DefaultCurrency = 'USD'; +var DefaultDspID = 124; +var DefaultTradingDeskID = 3456; +var DefaultCreativeID = 123234; +var DefaultBrandID = 123356; +var DefaultBrand = 'LA Tourism & Convention Board'; +var DefaultAdDoman = 2342342; +var DefaultPriceLevel = 1000; // only this is important? +var DefaultDeal = '515'; +var DefaultDealName = 'name: testdeal'; +var DefaultDealID = 'ixdl'; + +var ADAPTER_CODE = 'indexExchange'; + +exports.DefaultSiteID = DefaultSiteID; +exports.DefaultPlacementCodePrefix = DefaultPlacementCodePrefix; +exports.DefaultCurrency = DefaultCurrency; +exports.DefaultDspID = DefaultDspID; +exports.DefaultTradingDeskID = DefaultTradingDeskID; +exports.DefaultCreativeID = DefaultCreativeID; +exports.DefaultBrandID = DefaultBrandID; +exports.DefaultBrand = DefaultBrand; +exports.DefaultAdDoman = DefaultAdDoman; +exports.DefaultPriceLevel = DefaultPriceLevel; +exports.DefaultDeal = DefaultDeal; +exports.DefaultDealName = DefaultDealName; +exports.DefaultDealID = DefaultDealID; + +exports.ADAPTER_CODE = ADAPTER_CODE; function _createBidSlot(placementCode, indexSlotID, sizes, config) { - config = config || {}; - var bid = {}; - bid.bidder = ('bidder' in config) ? config.bidder : ADAPTER_CODE; - bid.placementCode = placementCode; - bid.params = {}; - bid.params.id = indexSlotID; - bid.params.siteID = ('siteID' in config) ? config.siteID : DefaultSiteID; - bid.sizes = sizes; - - //optional parameter - if ( typeof config.timeout !== 'undefined' ){ - bid.params.timeout = config.timeout; - } - if ( typeof config.tier2SiteID !== 'undefined' ){ - bid.params.tier2SiteID = config.tier2SiteID; - } - if ( typeof config.tier3SiteID !== 'undefined' ){ - bid.params.tier3SiteID = config.tier3SiteID; - } - if ( typeof config.slotSize !== 'undefined' ){ - bid.params.size = config.slotSize; - } - - //special parameter - if ( typeof(config.missingSlotID) !== 'undefined' ){ - delete bid.params.id; - } - if ( typeof(config.missingSiteID) !== 'undefined' ){ - delete bid.params.siteID; - } - - return bid; + config = config || {}; + var bid = {}; + bid.bidder = ('bidder' in config) ? config.bidder : ADAPTER_CODE; + bid.placementCode = placementCode; + bid.params = {}; + bid.params.id = indexSlotID; + bid.params.siteID = ('siteID' in config) ? config.siteID : DefaultSiteID; + bid.sizes = sizes; + + // optional parameter + if (typeof config.timeout !== 'undefined') { + bid.params.timeout = config.timeout; + } + if (typeof config.tier2SiteID !== 'undefined') { + bid.params.tier2SiteID = config.tier2SiteID; + } + if (typeof config.tier3SiteID !== 'undefined') { + bid.params.tier3SiteID = config.tier3SiteID; + } + if (typeof config.slotSize !== 'undefined') { + bid.params.size = config.slotSize; + } + + // special parameter + if (typeof (config.missingSlotID) !== 'undefined') { + delete bid.params.id; + } + if (typeof (config.missingSiteID) !== 'undefined') { + delete bid.params.siteID; + } + + return bid; } exports.createBidSlot = _createBidSlot; -exports.createBidSlots = function( numSlot, numSize ) { - if( typeof numSlot === 'undefined' ) numSlot = 1; - if( typeof numSize === 'undefined' ) numSize = 1; +exports.createBidSlots = function(numSlot, numSize) { + if (typeof numSlot === 'undefined') numSlot = 1; + if (typeof numSize === 'undefined') numSize = 1; - var bids = new Array( numSlot ); + var bids = new Array(numSlot); - var mkPlacementCode = function(i, j) { return DefaultPlacementCodePrefix + i + "_" + j; }; - for( var i=0; i [bid.ext.sid, bid])); - - var compared = compareOnKeys(lstore, rstore); - var matched = compared.intersection.map(function(pair) { return { configured: pair.left, sent: pair.right, name: pair.name } }); - - return { unmatched: { configured: compared.lhsOnly, sent: compared.rhsOnly } , matched: matched}; + var lonly = []; + var ronly = []; + + var configured = []; + for (var i = 0; i < lhs.length; i++) { + var group = lhs[i]; + for (var j = 0; j < group.length; j++) { + var bid = group[j]; + configured.push([bid.params.id + '_' + (j + 1), bid]); + + if (typeof bid.params.tier2SiteID !== 'undefined') { + configured.push(['T1_' + bid.params.id + '_' + (j + 1), bid]); + } + if (typeof bid.params.tier3SiteID !== 'undefined') { + configured.push(['T2_' + bid.params.id + '_' + (j + 1), bid]); + } + } + } + + var lstore = createObjectFromArray(configured); + var rstore = createObjectFromArray(rhs.map(bid => [bid.ext.sid, bid])); + + var compared = compareOnKeys(lstore, rstore); + var matched = compared.intersection.map(function(pair) { return { configured: pair.left, sent: pair.right, name: pair.name } }); + + return { unmatched: { configured: compared.lhsOnly, sent: compared.rhsOnly }, matched: matched}; } exports.matchBidsOnSize = function(lhs, rhs) { - var lonly = []; - var ronly = []; + var lonly = []; + var ronly = []; - var configured = []; - for (var i = 0; i < lhs.length; i++) { - var group = lhs[i]; - for (var j = 0; j < group.length; j++) { - var bid = group[j]; - configured.push([bid.size[0] + 'x' + bid.size[1], bid]); - } - } + var configured = []; + for (var i = 0; i < lhs.length; i++) { + var group = lhs[i]; + for (var j = 0; j < group.length; j++) { + var bid = group[j]; + configured.push([bid.size[0] + 'x' + bid.size[1], bid]); + } + } - var lstore = createObjectFromArray(configured); - var rstore = createObjectFromArray(rhs.map(bid => [ bid.banner.w + 'x' + bid.banner.h, bid])); + var lstore = createObjectFromArray(configured); + var rstore = createObjectFromArray(rhs.map(bid => [ bid.banner.w + 'x' + bid.banner.h, bid])); - var compared = compareOnKeys(lstore, rstore); - var matched = compared.intersection.map(function(pair) { return { configured: pair.left, sent: pair.right, name: pair.name } }); + var compared = compareOnKeys(lstore, rstore); + var matched = compared.intersection.map(function(pair) { return { configured: pair.left, sent: pair.right, name: pair.name } }); - return { unmatched: { configured: compared.lhsOnly, sent: compared.rhsOnly } , matched: matched}; + return { unmatched: { configured: compared.lhsOnly, sent: compared.rhsOnly }, matched: matched}; } -exports.getBidResponse = function( configuredBids, urlJSON, optionalPriceLevel, optionalResponseIdentifier, optionalPassOnBid, optionalResponseParam ) { - if( typeof configuredBids === 'undefined' || typeof urlJSON === 'undefined' ) return {}; - var response = {}; - - response.cur = DefaultCurrency; - response.id = urlJSON.r.id; - response.seatbid = []; - - optionalPassOnBid = optionalPassOnBid || []; - - var priceLevel = DefaultPriceLevel; - var adCount = 1; - - for( var i=0; i< configuredBids.length; i++ ) { - - var bidObj = {}; - bidObj.seat = (DefaultTradingDeskID+i).toString(); - bidObj.bid = []; - - var sizes = configuredBids[i].sizes; - var impressionID = 1; - for( var j=0; j { + storeStub = sinon.stub(videoCache, 'store'); + + if (responses.store instanceof Error) { + storeStub.callsArgWith(1, responses.store); + } else { + storeStub.callsArgWith(1, null, responses.store); + } + }); + + afterEach(() => { + videoCache.store.restore(); + }); + + return function() { + return { + store: storeStub + }; + } +} diff --git a/test/pages/video.html b/test/pages/video.html new file mode 100644 index 00000000000..755815111d1 --- /dev/null +++ b/test/pages/video.html @@ -0,0 +1,134 @@ + + + + + + Prebid.js video adUnit example + + + + + + + + + + + + + + + + + + +

Prebid Video -- video.js

+ +
+ + +
+ + + + diff --git a/test/spec/AnalyticsAdapter_spec.js b/test/spec/AnalyticsAdapter_spec.js new file mode 100644 index 00000000000..3eeb5a9efee --- /dev/null +++ b/test/spec/AnalyticsAdapter_spec.js @@ -0,0 +1,172 @@ +import { assert } from 'chai'; +import events from 'src/events'; +import CONSTANTS from 'src/constants.json'; + +const BID_REQUESTED = CONSTANTS.EVENTS.BID_REQUESTED; +const BID_RESPONSE = CONSTANTS.EVENTS.BID_RESPONSE; +const BID_WON = CONSTANTS.EVENTS.BID_WON; +const BID_TIMEOUT = CONSTANTS.EVENTS.BID_TIMEOUT; +const AnalyticsAdapter = require('src/AnalyticsAdapter').default; +const config = { + url: 'http://localhost:9999/src/adapters/analytics/libraries/example.js', + analyticsType: 'library', + global: 'ExampleAnalyticsGlobalObject', + handler: 'on' +}; + +window[config.global] = () => {}; + +describe(` +FEATURE: Analytics Adapters API + SCENARIO: A publisher enables analytics + GIVEN a global object \`window['testGlobal']\` + AND an \`example\` instance of \`AnalyticsAdapter\`\n`, () => { + describe(`WHEN an event occurs that is to be tracked\n`, () => { + const eventType = BID_REQUESTED; + const args = { some: 'data' }; + const adapter = new AnalyticsAdapter(config); + var spyTestGlobal = sinon.spy(window, config.global); + + adapter.track({ eventType, args }); + + it(`THEN should call \`window.${config.global}\` function\n`, () => { + assert.ok(spyTestGlobal.args[0][1] === eventType, `with expected event type\n`); + assert.deepEqual(spyTestGlobal.args[0][2], args, `with expected event data\n`); + }); + window[config.global].restore(); + }); + + describe(`WHEN an event occurs before tracking library is available\n`, () => { + const eventType = BID_RESPONSE; + const args = { wat: 'wot' }; + const adapter = new AnalyticsAdapter(config); + + window[config.global] = null; + events.emit(BID_RESPONSE, args); + + describe(`AND the adapter is then enabled\n`, () => { + window[config.global] = () => {}; + + var spyTestGlobal = sinon.spy(window, config.global); + + adapter.enableAnalytics(); + + it(`THEN should queue the event first and then track it\n`, () => { + assert.ok(spyTestGlobal.args[0][1] === eventType, `with expected event type\n`); + assert.deepEqual(spyTestGlobal.args[0][2], args, `with expected event data\n`); + }); + + adapter.disableAnalytics(); + window[config.global].restore(); + }); + }); + + describe(`WHEN an event occurs after enable analytics\n`, () => { + var spyTestGlobal, + adapter; + + beforeEach(() => { + adapter = new AnalyticsAdapter(config); + spyTestGlobal = sinon.spy(window, config.global); + + sinon.stub(events, 'getEvents', () => []); // these tests shouldn't be affected by previous tests + }); + + afterEach(() => { + adapter.disableAnalytics(); + window[config.global].restore(); + + events.getEvents.restore(); + }); + + it('SHOULD call global when a bidWon event occurs', () => { + const eventType = BID_WON; + const args = { more: 'info' }; + + adapter.enableAnalytics(); + events.emit(eventType, args); + + assert.ok(spyTestGlobal.args[0][1] === eventType, `with expected event type\n`); + assert.deepEqual(spyTestGlobal.args[0][2], args, `with expected event data\n`); + }); + + it('SHOULD call global when a bidRequest event occurs', () => { + const eventType = BID_REQUESTED; + const args = { call: 'request' }; + + adapter.enableAnalytics(); + events.emit(eventType, args); + + assert.ok(spyTestGlobal.args[0][1] === eventType, `with expected event type\n`); + assert.deepEqual(spyTestGlobal.args[0][2], args, `with expected event data\n`); + }); + + it('SHOULD call global when a bidResponse event occurs', () => { + const eventType = BID_RESPONSE; + const args = { call: 'response' }; + + adapter.enableAnalytics(); + events.emit(eventType, args); + + assert.ok(spyTestGlobal.args[0][1] === eventType, `with expected event type\n`); + assert.deepEqual(spyTestGlobal.args[0][2], args, `with expected event data\n`); + }); + + it('SHOULD call global when a bidTimeout event occurs', () => { + const eventType = BID_TIMEOUT; + const args = { call: 'timeout' }; + + adapter.enableAnalytics(); + events.emit(eventType, args); + + assert.ok(spyTestGlobal.args[0][1] === eventType, `with expected event type\n`); + assert.deepEqual(spyTestGlobal.args[0][2], args, `with expected event data\n`); + }); + + it('SHOULD NOT call global again when adapter.enableAnalytics is called with previous timeout', () => { + const eventType = BID_TIMEOUT; + const args = { call: 'timeout' }; + + events.emit(eventType, args); + adapter.enableAnalytics(); + events.emit(eventType, args); + + assert(spyTestGlobal.calledOnce === true); + }); + + describe(`AND sampling is enabled\n`, () => { + const eventType = BID_WON; + const args = { more: 'info' }; + + beforeEach(() => { + sinon.stub(Math, 'random', () => 0.5); + }); + + afterEach(() => { + Math.random.restore(); + }); + + it(`THEN should enable analytics when random number is in sample range`, () => { + adapter.enableAnalytics({ + options: { + sampling: 0.75 + } + }); + events.emit(eventType, args); + + assert(spyTestGlobal.called === true); + }); + + it(`THEN should disable analytics when random number is outside sample range`, () => { + adapter.enableAnalytics({ + options: { + sampling: 0.25 + } + }); + events.emit(eventType, args); + + assert(spyTestGlobal.called === false); + }); + }); + }); + }); diff --git a/test/spec/adUnits_spec.js b/test/spec/adUnits_spec.js index 280ccc1eb16..01a4c4cd441 100644 --- a/test/spec/adUnits_spec.js +++ b/test/spec/adUnits_spec.js @@ -8,38 +8,38 @@ describe('Publisher API _ AdUnits', function () { code: '/1996833/slot-1', sizes: [[300, 250], [728, 90]], bids: [ - { - bidder: 'openx', - params: { - pgid: '2342353', - unit: '234234', - jstag_url: 'http://' - } - }, { - bidder: 'appnexus', - params: { - placementId: '234235' - } - } - ] + { + bidder: 'openx', + params: { + pgid: '2342353', + unit: '234234', + jstag_url: 'http://' + } + }, { + bidder: 'appnexus', + params: { + placementId: '234235' + } + } + ] }, { code: '/1996833/slot-2', sizes: [[468, 60]], bids: [ - { - bidder: 'rubicon', - params: { - rp_account: '4934', - rp_site: '13945', - rp_zonesize: '23948-15' - } - }, { - bidder: 'appnexus', - params: { - placementId: '827326' - } - } - ] + { + bidder: 'rubicon', + params: { + rp_account: '4934', + rp_site: '13945', + rp_zonesize: '23948-15' + } + }, { + bidder: 'appnexus', + params: { + placementId: '827326' + } + } + ] }]; pbjsTestOnly.clearAllAdUnits(); $$PREBID_GLOBAL$$.addAdUnits(adUnits); @@ -50,7 +50,6 @@ describe('Publisher API _ AdUnits', function () { }); describe('addAdUnits', function () { - var adUnits, adUnit1, bids1, adUnit2, bids2; it('should have two adUnits', function () { @@ -83,7 +82,7 @@ describe('Publisher API _ AdUnits', function () { assert.strictEqual(bids2[1].params.placementId, '827326', 'adUnit2 bids2 params.placementId'); }); - it ('both add unit should contains a transactionid.'), function() { + it('both add unit should contains a transactionid.'), function() { assert.exist(adUnit1.transationId) assert.exist(adUnit2.transationId) @@ -91,7 +90,6 @@ describe('Publisher API _ AdUnits', function () { } it('the second adUnits value should be same with the adUnits that is added by $$PREBID_GLOBAL$$.addAdUnits();', function () { - assert.strictEqual(adUnit2.code, '/1996833/slot-2', 'adUnit2 code'); assert.deepEqual(adUnit2.sizes, [[468, 60]], 'adUnit2 sizes'); assert.strictEqual(bids2[0].bidder, 'rubicon', 'adUnit2 bids1 bidder'); @@ -105,7 +103,6 @@ describe('Publisher API _ AdUnits', function () { }); describe('removeAdUnit', function () { - var adUnits, adUnit2, bids2; it('the first adUnit should be not existed', function () { @@ -128,5 +125,4 @@ describe('Publisher API _ AdUnits', function () { assert.strictEqual(bids2[1].params.placementId, '827326', 'adUnit2 bids2 params.placementId'); }); }); - }); diff --git a/test/spec/adapters/adbund_spec.js b/test/spec/adapters/adbund_spec.js deleted file mode 100644 index 0714d041c83..00000000000 --- a/test/spec/adapters/adbund_spec.js +++ /dev/null @@ -1,96 +0,0 @@ -import { expect } from 'chai'; -import Adapter from '../../../src/adapters/adbund'; -import bidManager from 'src/bidmanager'; -import CONSTANTS from 'src/constants.json'; - -describe('adbund adapter tests', function () { - - let sandbox; - let adapter; - let server; - - const request = { - bidderCode: 'adbund', - bids: [{ - bidder: 'adbund', - params: { - sid: '110238', - bidfloor: 0.036 - }, - placementCode: 'adbund', - sizes: [[300, 250]], - bidId: 'adbund_bidId', - bidderRequestId: 'adbund_bidderRequestId', - requestId: 'adbund_requestId' - }] - }; - - const response = { - bidderCode: 'adbund', - cpm: 1.06, - height: 250, - width: 300 - }; - - beforeEach(() => { - sandbox = sinon.sandbox.create(); - }); - - afterEach(() => { - sandbox.restore(); - }); - - describe('adbund callBids validation', () => { - - beforeEach(() => { - adapter = new Adapter(); - }); - - afterEach(() => { - }); - - it('Valid bid-request', () => { - let bidderRequest; - - sandbox.stub(adapter, 'callBids'); - adapter.callBids(request); - - bidderRequest = adapter.callBids.getCall(0).args[0]; - - expect(bidderRequest).to.have.property('bids') - .that.is.an('array') - .with.lengthOf(1); - - expect(bidderRequest).to.have.deep.property('bids[0]') - .to.have.property('bidder', 'adbund'); - - expect(bidderRequest).to.have.deep.property('bids[0]') - .with.property('sizes') - .that.is.an('array') - .with.lengthOf(1) - .that.deep.equals(request.bids[0].sizes); - - expect(bidderRequest).to.have.deep.property('bids[0]') - .with.property('params') - .to.have.property('bidfloor', 0.036); - }); - - it('Valid bid-response', () => { - var bidderResponse; - - sandbox.stub(bidManager, 'addBidResponse'); - adapter.callBids(request); - bidderResponse = bidManager.addBidResponse.getCall(0) || - bidManager.addBidResponse.getCall(1); - - if (bidderResponse && bidderResponse.args && bidderResponse.args[1]) { - bidderResponse = bidderResponse.args[1]; - expect(bidderResponse.getStatusCode()).to.equal(CONSTANTS.STATUS.GOOD); - expect(bidderResponse.bidderCode).to.equal(response.bidderCode); - expect(bidderResponse.width).to.equal(response.width); - expect(bidderResponse.height).to.equal(response.height); - expect(bidderResponse.cpm).to.equal(response.cpm); - } - }); - }); -}); \ No newline at end of file diff --git a/test/spec/adapters/adbutler_spec.js b/test/spec/adapters/adbutler_spec.js deleted file mode 100644 index 172c2205210..00000000000 --- a/test/spec/adapters/adbutler_spec.js +++ /dev/null @@ -1,543 +0,0 @@ -describe('adbutler adapter tests', function () { - - var expect = require('chai').expect; - var adapter = require('src/adapters/adbutler'); - var adLoader = require('src/adloader'); - var bidmanager = require('src/bidmanager'); - - window.pbjs = window.pbjs || {}; - if (typeof(pbjs)==="undefined"){ - var pbjs = window.pbjs; - } - - describe('creation of bid url', function () { - - var stubLoadScript; - - beforeEach(function () { - stubLoadScript = sinon.stub(adLoader, 'loadScript'); - }); - - afterEach(function () { - stubLoadScript.restore(); - }); - - if (typeof(pbjs._bidsReceived) === "undefined") { - pbjs._bidsReceived = []; - } - if (typeof(pbjs._bidsRequested) === "undefined") { - pbjs._bidsRequested = []; - } - if (typeof(pbjs._adsReceived) === "undefined") { - pbjs._adsReceived = []; - } - - it('should be called', function () { - - var params = { - bidderCode: 'adbutler', - bids: [ - { - bidId: '3c9408cdbf2f68', - sizes: [[300, 250]], - bidder: 'adbutler', - params: { - accountID: '167283', - zoneID: '210093' - }, - requestId: '10b327aa396609', - placementCode: '/123456/header-bid-tag-1' - } - - ] - }; - - adapter().callBids(params); - - sinon.assert.called(stubLoadScript); - - }); - - it('should populate the keyword',function(){ - var params = { - bidderCode: 'adbutler', - bids: [ - { - bidId: '3c9408cdbf2f68', - sizes: [[300, 250]], - bidder: 'adbutler', - params: { - accountID: '167283', - zoneID: '210093', - keyword: 'fish' - }, - requestId: '10b327aa396609', - placementCode: '/123456/header-bid-tag-1' - } - - ] - }; - - adapter().callBids(params); - - var requestURI = stubLoadScript.getCall(0).args[0]; - - expect(requestURI).to.have.string(';kw=fish;'); - }); - - it('should use custom domain string',function(){ - var params = { - bidderCode: 'adbutler', - bids: [ - { - bidId: '3c9408cdbf2f68', - sizes: [[300, 250]], - bidder: 'adbutler', - params: { - accountID: '107878', - zoneID: '86133', - domain: 'servedbyadbutler.com.dan.test' - }, - requestId: '10b327aa396609', - placementCode: '/123456/header-bid-tag-1' - } - ] - }; - - adapter().callBids(params); - - var requestURI = stubLoadScript.getCall(0).args[0]; - - expect(requestURI).to.have.string('.dan.test'); - }); - }); - describe('bid responses',function(){ - - it('should return complete bid response',function(){ - var stubAddBidResponse = sinon.stub(bidmanager, 'addBidResponse'); - - var params = { - bidderCode: 'adbutler', - bidder: 'adbutler', - bids: [ - { - bidId: '3c94018cdbf2f68-1', - sizes: [[300, 250]], - bidder: 'adbutler', - params: { - accountID: '167283', - zoneID: '210093', - }, - requestId: '10b327aa396609', - placementCode: '/123456/header-bid-tag-1' - } - - ] - }; - - var response = { - status: "SUCCESS", - account_id: 167283, - zone_id: 210093, - cpm: 1.5, - width: 300, - height: 250, - place: 0 - }; - - adapter().callBids(params); - - var adUnits = new Array(); - var unit = new Object(); - unit.bids = params.bids; - unit.code = '/123456/header-bid-tag-1'; - unit.sizes=[[300,250]]; - adUnits.push(unit); - - if (typeof(pbjs._bidsRequested)==="undefined"){ - pbjs._bidsRequested = [params]; - } - else{ - pbjs._bidsRequested.push(params); - } - - pbjs.adUnits = adUnits; - - - pbjs.adbutlerCB(response); - - var bidPlacementCode1 = stubAddBidResponse.getCall(0).args[0]; - var bidObject1 = stubAddBidResponse.getCall(0).args[1]; - - expect(bidPlacementCode1).to.equal('/123456/header-bid-tag-1'); - expect(bidObject1.getStatusCode()).to.equal(1); - expect(bidObject1.bidderCode).to.equal('adbutler'); - expect(bidObject1.cpm).to.equal(1.5); - expect(bidObject1.width).to.equal(300); - expect(bidObject1.height).to.equal(250); - - stubAddBidResponse.restore(); - }); - - it('should return empty bid response', function(){ - - var stubAddBidResponse = sinon.stub(bidmanager, 'addBidResponse'); - var params = { - bidderCode: 'adbutler', - bids: [ - { - bidId: '3c9408cdbf2f68-2', - sizes: [[300, 250]], - bidder: 'adbutler', - params: { - accountID: '167283', - zoneID: '210085', - }, - requestId: '10b327aa396609', - placementCode: '/123456/header-bid-tag-1' - } - - ] - }; - - var response = { - status: "NO_ELIGIBLE_ADS", - zone_id: 210085, - width: 728, - height: 90, - place: 0 - }; - - adapter().callBids(params); - - var adUnits = new Array(); - var unit = new Object(); - unit.bids = params.bids; - unit.code = '/123456/header-bid-tag-1'; - unit.sizes=[[300,250]]; - adUnits.push(unit); - - if (typeof(pbjs._bidsRequested)==="undefined"){ - pbjs._bidsRequested = [params]; - } - else{ - pbjs._bidsRequested.push(params); - } - - pbjs.adUnits = adUnits; - - pbjs.adbutlerCB(response); - - var bidPlacementCode1 = stubAddBidResponse.getCall(0).args[0]; - var bidObject1 = stubAddBidResponse.getCall(0).args[1]; - - expect(bidPlacementCode1).to.equal('/123456/header-bid-tag-1'); - expect(bidObject1.getStatusCode()).to.equal(2); - expect(bidObject1.bidderCode).to.equal('adbutler'); - - stubAddBidResponse.restore(); - }); - - it('should return empty bid response on incorrect size',function(){ - - var stubAddBidResponse = sinon.stub(bidmanager, 'addBidResponse'); - var params = { - bidderCode: 'adbutler', - bids: [ - { - bidId: '3c9408cdbf2f68-3', - sizes: [[300, 250]], - bidder: 'adbutler', - params: { - accountID: '167283', - zoneID: '210085', - }, - requestId: '10b327aa396609', - placementCode: '/123456/header-bid-tag-1' - } - - ] - }; - - var response = { - status: "SUCCESS", - account_id: 167283, - zone_id: 210085, - cpm: 1.5, - width: 728, - height: 90, - place: 0 - }; - - adapter().callBids(params); - - var adUnits = new Array(); - var unit = new Object(); - unit.bids = params.bids; - unit.code = '/123456/header-bid-tag-1'; - unit.sizes=[[300,250]]; - adUnits.push(unit); - - if (typeof(pbjs._bidsRequested)==="undefined"){ - pbjs._bidsRequested = [params]; - } - else{ - pbjs._bidsRequested.push(params); - } - - pbjs.adUnits = adUnits; - - pbjs.adbutlerCB(response); - - var bidObject1 = stubAddBidResponse.getCall(0).args[1]; - expect(bidObject1.getStatusCode()).to.equal(2); - - stubAddBidResponse.restore(); - }); - - it('should return empty bid response with CPM too low',function(){ - - var stubAddBidResponse = sinon.stub(bidmanager, 'addBidResponse'); - var params = { - bidderCode: 'adbutler', - bids: [ - { - bidId: '3c9408cdbf2f68-4', - sizes: [[300, 250]], - bidder: 'adbutler', - params: { - accountID: '167283', - zoneID: '210093', - minCPM: '5.00' - }, - requestId: '10b327aa396609', - placementCode: '/123456/header-bid-tag-1' - } - - ] - }; - - var response = { - status: "SUCCESS", - account_id: 167283, - zone_id: 210093, - cpm: 1.5, - width: 300, - height: 250, - place: 0 - }; - - adapter().callBids(params); - - var adUnits = new Array(); - var unit = new Object(); - unit.bids = params.bids; - unit.code = '/123456/header-bid-tag-1'; - unit.sizes=[[300,250]]; - adUnits.push(unit); - - if (typeof(pbjs._bidsRequested)==="undefined"){ - pbjs._bidsRequested = [params]; - } - else{ - pbjs._bidsRequested.push(params); - } - - pbjs.adUnits = adUnits; - - pbjs.adbutlerCB(response); - - var bidObject1 = stubAddBidResponse.getCall(0).args[1]; - expect(bidObject1.getStatusCode()).to.equal(2); - - stubAddBidResponse.restore(); - }); - - it('should return empty bid response with CPM too high',function(){ - - var stubAddBidResponse = sinon.stub(bidmanager, 'addBidResponse'); - - var params = { - bidderCode: 'adbutler', - bids: [ - { - bidId: '3c9408cdbf2f68-5', - sizes: [[300, 250]], - bidder: 'adbutler', - params: { - accountID: '167283', - zoneID: '210093', - maxCPM: '1.00' - }, - requestId: '10b327aa396609', - placementCode: '/123456/header-bid-tag-1' - } - - ] - }; - - var response = { - status: "SUCCESS", - account_id: 167283, - zone_id: 210093, - cpm: 1.5, - width: 300, - height: 250, - place: 0 - }; - - adapter().callBids(params); - - var adUnits = new Array(); - var unit = new Object(); - unit.bids = params.bids; - unit.code = '/123456/header-bid-tag-1'; - unit.sizes=[[300,250]]; - adUnits.push(unit); - - if (typeof(pbjs._bidsRequested)==="undefined"){ - pbjs._bidsRequested = [params]; - } - else{ - pbjs._bidsRequested.push(params); - } - - pbjs.adUnits = adUnits; - - pbjs.adbutlerCB(response); - - var bidObject1 = stubAddBidResponse.getCall(0).args[1]; - expect(bidObject1.getStatusCode()).to.equal(2); - - stubAddBidResponse.restore(); - }); - - }); - - describe('ad code',function(){ - - it('should be populated',function(){ - - var stubAddBidResponse = sinon.stub(bidmanager, 'addBidResponse'); - - var params = { - bidderCode: 'adbutler', - bids: [ - { - bidId: '3c9408cdbf2f68-6', - sizes: [[300, 250]], - bidder: 'adbutler', - params: { - accountID: '167283', - zoneID: '210093' - }, - requestId: '10b327aa396609', - placementCode: '/123456/header-bid-tag-1' - } - - ] - }; - - var response = { - status: "SUCCESS", - account_id: 167283, - zone_id: 210093, - cpm: 1.5, - width: 300, - height: 250, - place: 0, - ad_code: '' - }; - - adapter().callBids(params); - - var adUnits = new Array(); - var unit = new Object(); - unit.bids = params.bids; - unit.code = '/123456/header-bid-tag-1'; - unit.sizes=[[300,250]]; - adUnits.push(unit); - - if (typeof(pbjs._bidsRequested)==="undefined"){ - pbjs._bidsRequested = [params]; - } - else{ - pbjs._bidsRequested.push(params); - } - - pbjs.adUnits = adUnits; - - pbjs.adbutlerCB(response); - - var bidObject1 = stubAddBidResponse.getCall(0).args[1]; - expect(bidObject1.getStatusCode()).to.equal(1); - expect(bidObject1.ad).to.have.length.above(1); - - stubAddBidResponse.restore(); - }); - - it('should contain tracking pixels',function(){ - - var stubAddBidResponse = sinon.stub(bidmanager, 'addBidResponse'); - - var params = { - bidderCode: 'adbutler', - bids: [ - { - bidId: '3c9408cdbf2f68-7', - sizes: [[300, 250]], - bidder: 'adbutler', - params: { - accountID: '167283', - zoneID: '210093' - }, - requestId: '10b327aa396609', - placementCode: '/123456/header-bid-tag-1' - } - - ] - }; - - var response = { - status: "SUCCESS", - account_id: 167283, - zone_id: 210093, - cpm: 1.5, - width: 300, - height: 250, - place: 0, - ad_code: '', - tracking_pixels: [ - "http://tracking.pixel.com/params=info" - ] - }; - - adapter().callBids(params); - - var adUnits = new Array(); - var unit = new Object(); - unit.bids = params.bids; - unit.code = '/123456/header-bid-tag-1'; - unit.sizes=[[300,250]]; - adUnits.push(unit); - - if (typeof(pbjs._bidsRequested)==="undefined"){ - pbjs._bidsRequested = [params]; - } - else{ - pbjs._bidsRequested.push(params); - } - - pbjs.adUnits = adUnits; - - pbjs.adbutlerCB(response); - - var bidObject1 = stubAddBidResponse.getCall(0).args[1]; - expect(bidObject1.getStatusCode()).to.equal(1); - expect(bidObject1.ad).to.have.string('http://tracking.pixel.com/params=info'); - - stubAddBidResponse.restore(); - }); - - }); -}); \ No newline at end of file diff --git a/test/spec/adapters/admixer_spec.js b/test/spec/adapters/admixer_spec.js deleted file mode 100644 index a49a2b4b230..00000000000 --- a/test/spec/adapters/admixer_spec.js +++ /dev/null @@ -1,138 +0,0 @@ -window.pbjs = window.pbjs || {}; -var chai = require('chai'); -var Adapter = require('src/adapters/admixer')(); -var Ajax = require('src/ajax'); -var bidmanager = require('src/bidmanager.js'); -var CONSTANTS = require('src/constants.json'); - -describe('Admixer adapter', function () { - var validData_1 = { - bids: [ - { - bidder: 'admixer', - bidId: 'bid_id', - params: {zone: 'zone_id'}, - placementCode: 'ad-unit-1', - sizes: [[300, 250], [300, 600]] - } - ] - }; - var validData_2 = { - bids: [ - { - bidder: 'admixer', - bidId: 'bid_id', - params: {zone: 'zone_id'}, - placementCode: 'ad-unit-1', - sizes: [300, 250] - } - ] - }; - var invalidData = { - bids: [ - { - bidder: 'admixer', - bidId: 'bid_id', - params: {}, - placementCode: 'ad-unit-1', - sizes: [[300, 250], [300, 600]] - } - ] - }; - var responseWithAd = JSON.stringify({ - 'result': { - 'cpm': 2.2, - 'ad': '
response ad
', - 'width': 300, - 'height': 250 - }, - 'callback_uid': 'ad-unit-1' - }); - var responseWithoutAd = JSON.stringify({ - 'result': { - 'cpm': 0, - 'ad': '', - 'width': 0, - 'height': 0 - }, - 'callback_uid': 'ad-unit-1' - }); - var responseEmpty = ''; - var invUrl = '//inv-nets.admixer.net/prebid.aspx'; - var validJsonParams = { - zone: 'zone_id', - callback_uid: 'ad-unit-1', - sizes: '300x250-300x600' - }; - describe('bid request with valid data', function () { - var stubAjax; - beforeEach(function () { - stubAjax = sinon.stub(Ajax, 'ajax'); - }); - - afterEach(function () { - stubAjax.restore(); - }); - it('bid request should be called. sizes style -> [[],[]]', function () { - Adapter.callBids(validData_1); - sinon.assert.calledOnce(stubAjax); - }); - it('bid request should be called. sizes style -> []', function () { - Adapter.callBids(validData_2); - sinon.assert.calledOnce(stubAjax); - }); - it('ajax params should be matched', function () { - Adapter.callBids(validData_1); - sinon.assert.calledWith(stubAjax, sinon.match(invUrl, function () { - }, validJsonParams, {method: "GET"})); - }); - }); - describe('bid request with invalid data', function () { - var addBidResponse, stubAjax; - beforeEach(function () { - addBidResponse = sinon.stub(bidmanager, 'addBidResponse'); - stubAjax = sinon.stub(Ajax, 'ajax'); - }); - - afterEach(function () { - addBidResponse.restore(); - stubAjax.restore(); - }); - it('ajax shouldn\'t be called', function () { - Adapter.callBids(invalidData); - sinon.assert.notCalled(stubAjax); - }); - it('bidmanager.addBidResponse status code must to be equal "' + CONSTANTS.STATUS.NO_BID + '"', function () { - Adapter.callBids(invalidData); - expect(addBidResponse.firstCall.args[1].getStatusCode()).to.equal(CONSTANTS.STATUS.NO_BID); - expect(addBidResponse.firstCall.args[1].bidderCode).to.equal('admixer'); - }); - }); - describe('bid response', function () { - var addBidResponse; - beforeEach(function () { - addBidResponse = sinon.stub(bidmanager, 'addBidResponse'); - }); - afterEach(function () { - addBidResponse.restore(); - }); - it('response with ad. bidmanager.addBidResponse status code must to be equal "' + CONSTANTS.STATUS.GOOD + '"', function () { - Adapter.responseCallback(responseWithAd); - var arg = addBidResponse.firstCall.args[1]; - expect(arg.getStatusCode()).to.equal(CONSTANTS.STATUS.GOOD); - expect(arg.bidderCode).to.equal('admixer'); - }); - it('response without ad. bidmanager.addBidResponse status code must to be equal "' + CONSTANTS.STATUS.NO_BID, function () { - Adapter.responseCallback(responseWithoutAd); - var arg = addBidResponse.firstCall.args[1]; - expect(arg.getStatusCode()).to.equal(CONSTANTS.STATUS.NO_BID); - expect(arg.bidderCode).to.equal('admixer'); - }); - it('response empty. bidmanager.addBidResponse status code must to be equal "' + CONSTANTS.STATUS.NO_BID, function () { - Adapter.responseCallback(responseEmpty); - var arg = addBidResponse.firstCall.args[1]; - expect(arg.getStatusCode()).to.equal(CONSTANTS.STATUS.NO_BID); - expect(arg.bidderCode).to.equal('admixer'); - }) - }); -}); \ No newline at end of file diff --git a/test/spec/adapters/adsupply_spec.js b/test/spec/adapters/adsupply_spec.js deleted file mode 100644 index 0798f9821d7..00000000000 --- a/test/spec/adapters/adsupply_spec.js +++ /dev/null @@ -1,359 +0,0 @@ -describe('adsupply adapter tests', function () { - - const expect = require('chai').expect; - - const AdSupplyAdapter = require('../../../src/adapters/adsupply'); - const adloader = require('../../../src/adloader'); - const bidmanager = require('../../../src/bidmanager'); - const CONSTANTS = require('../../../src/constants.json'); - let adsupplyAdapter = new AdSupplyAdapter(); - - //before(() => sinon.stub(document.body, 'appendChild')); - //after(() => document.body.appendChild.restore()); - - it('adsupply response handler should exist and be a function', function () { - expect(pbjs.adSupplyResponseHandler).to.exist.and.to.be.a('function'); - }); - - it('two requests are sent to adsupply engine', function () { - let stubLoadScript = sinon.stub(adloader, 'loadScript'); - - let request = { - bids: [{ - placementCode: "pc1", - bidder: "adsupply", - bidId: 'bidId1', - params: { - zoneId: 111, - clientId: 'g32db6906-55f4-42b1-a7d2-7dfaddce96fd', - siteId: '0ab16161-a1de-4683-8837-c420bd4387c0', - endpointUrl: 'engine.4dsply.com' - } - }, - { - placementCode: "pc2", - bidder: "adsupply", - bidId: 'bidId2', - params: { - clientId: 'g32db6906-55f4-42b1-a7d2-7dfaddce96fd', - zoneId: 222, - siteId: '0ab16161-a1de-4683-8837-c420bd4387c0', - endpointUrl: 'engine.4dsply.com' - } - }] - }; - - adsupplyAdapter.callBids(request); - - sinon.assert.calledTwice(stubLoadScript); - - adloader.loadScript.restore(); - }); - - it('zoneId is not a number and not specified', function () { - let stubLoadScript = sinon.stub(adloader, 'loadScript'); - - let request = { - bids: [{ - placementCode: "pc1", - bidder: "adsupply", - bidId: 'bidId1', - params: { - clientId: 'g32db6906-55f4-42b1-a7d2-7dfaddce96fd', - zoneId: '111', - siteId: '0ab16161-a1de-4683-8837-c420bd4387c0', - endpointUrl: 'engine.4dsply.com' - } - }, - { - placementCode: "pc2", - bidder: "adsupply", - bidId: 'bidId2', - params: { - clientId: 'g32db6906-55f4-42b1-a7d2-7dfaddce96fd', - siteId: '0ab16161-a1de-4683-8837-c420bd4387c0', - endpointUrl: 'engine.4dsply.com' - } - }] - }; - - adsupplyAdapter.callBids(request); - - sinon.assert.notCalled(stubLoadScript); - - adloader.loadScript.restore(); - }); - - it('siteId is empty and not specified', function () { - let stubLoadScript = sinon.stub(adloader, 'loadScript'); - - let request = { - bids: [{ - placementCode: "pc1", - bidder: "adsupply", - bidId: 'bidId1', - params: { - zoneId: 111, - siteId: '', - clientId: 'g32db6906-55f4-42b1-a7d2-7dfaddce96fd', - endpointUrl: 'engine.4dsply.com' - } - }, - { - placementCode: "pc2", - bidder: "adsupply", - bidId: 'bidId2', - params: { - zoneId: 222, - clientId: 'g32db6906-55f4-42b1-a7d2-7dfaddce96fd', - endpointUrl: 'engine.4dsply.com' - } - }] - }; - - adsupplyAdapter.callBids(request); - - sinon.assert.notCalled(stubLoadScript); - - adloader.loadScript.restore(); - }); - - it('endpointUrl is empty and not specified', function () { - let stubLoadScript = sinon.stub(adloader, 'loadScript'); - - let request = { - bids: [{ - placementCode: "pc1", - bidder: "adsupply", - bidId: 'bidId1', - params: { - clientId: 'g32db6906-55f4-42b1-a7d2-7dfaddce96fd', - zoneId: 111, - siteId: '0ab16161-a1de-4683-8837-c420bd4387c0', - endpointUrl: '' - } - }, - { - placementCode: "pc2", - bidder: "adsupply", - bidId: 'bidId2', - params: { - clientId: 'g32db6906-55f4-42b1-a7d2-7dfaddce96fd', - zoneId: 222, - siteId: '0ab16161-a1de-4683-8837-c420bd4387c0', - } - }] - }; - - adsupplyAdapter.callBids(request); - - sinon.assert.notCalled(stubLoadScript); - - adloader.loadScript.restore(); - }); - - it('clientId is empty and not specified', function () { - let stubLoadScript = sinon.stub(adloader, 'loadScript'); - - let request = { - bids: [{ - placementCode: "pc1", - bidder: "adsupply", - bidId: 'bidId1', - params: { - clientId: '', - zoneId: 111, - siteId: '0ab16161-a1de-4683-8837-c420bd4387c0', - endpointUrl: 'engine.4dsply.com' - } - }, - { - placementCode: "pc2", - bidder: "adsupply", - bidId: 'bidId2', - params: { - zoneId: 222, - siteId: '0ab16161-a1de-4683-8837-c420bd4387c0', - endpointUrl: 'engine.4dsply.com' - } - }] - }; - - adsupplyAdapter.callBids(request); - - sinon.assert.notCalled(stubLoadScript); - - adloader.loadScript.restore(); - }); - - it('parameters are missed', function () { - let stubLoadScript = sinon.stub(adloader, 'loadScript'); - - let request = { - bids: [{ - placementCode: "pc1", - bidder: "adsupply", - bidId: 'bidId1' - }] - }; - - adsupplyAdapter.callBids(request); - - sinon.assert.notCalled(stubLoadScript); - - adloader.loadScript.restore(); - }); - - it('Parameters added to the request url', function () { - let stubLoadScript = sinon.stub(adloader, 'loadScript'); - - let request = { - bids: [{ - placementCode: "pc1", - bidder: "adsupply", - bidId: 'bidId1', - params: { - zoneId: 111, - clientId: 'g32db6906-55f4-42b1-a7d2-7dfaddce96fd', - siteId: '0ab16161-a1de-4683-8837-c420bd4387c0', - endpointUrl: 'engine.4dsply.com' - } - }] - }; - - adsupplyAdapter.callBids(request); - - var requestUrl = stubLoadScript.getCall(0).args[0]; - expect(requestUrl).to.contain('111'); - expect(requestUrl).to.contain('0ab16161-a1de-4683-8837-c420bd4387c0'); - expect(requestUrl).to.contain('engine.4dsply.com'); - expect(requestUrl).to.contain('&hbt=1'); - expect(requestUrl).to.contain('g32db6906-55f4-42b1-a7d2-7dfaddce96fd'); - - adloader.loadScript.restore(); - }); - - it('Response handler invalid data', function () { - let stubAddBidResponse = sinon.stub(bidmanager, 'addBidResponse'); - - // adapter needs to be called, in order for the stub to register. - new AdSupplyAdapter(); - - // bidId is not valid - pbjs.adSupplyResponseHandler(null); - - // bidRequest object is not found - pbjs.adSupplyResponseHandler('bidId1'); - - let clientId = 'g5d384afa-c050-4bac-b202-dab8fb06e381'; - //Zone property is not found - let bidderRequest = { - bidderCode: 'adsupply', - bids: [{ - placementCode: "pc1", - bidder: "adsupply", - bidId: 'bidId1', - params: { - clientId: clientId, - zoneId: 111, - siteId: '0ab16161-a1de-4683-8837-c420bd4387c0', - endpointUrl: 'engine.4dsply.com' - } - }] - }; - pbjs._bidsRequested.push(bidderRequest); - pbjs.adSupplyResponseHandler('bidId1'); - - //Media is not found - window[clientId] = window[clientId] || {}; - window[clientId]['b111'] = window[clientId]['b111'] || {}; - pbjs.adSupplyResponseHandler('bidId1'); - - sinon.assert.notCalled(stubAddBidResponse); - - pbjs._bidsRequested.pop(); - bidmanager.addBidResponse.restore(); - }); - - it('No Fill response', function () { - let stubAddBidResponse = sinon.stub(bidmanager, 'addBidResponse'); - // adapter needs to be called, in order for the stub to register. - new AdSupplyAdapter(); - - let clientId = 'g5d384afa-c050-4bac-b202-dab8fb06e381'; - //Zone property is not found - let bidderRequest = { - bidderCode: 'adsupply', - bids: [{ - placementCode: "pc1", - bidder: "adsupply", - bidId: 'bidId1', - params: { - clientId: clientId, - zoneId: 111, - siteId: '0ab16161-a1de-4683-8837-c420bd4387c0', - endpointUrl: 'engine.4dsply.com' - } - }] - }; - - pbjs._bidsRequested.push(bidderRequest); - - window[clientId] = window[clientId] || {}; - window[clientId]['b111'] = window[clientId]['b111'] || {}; - window[clientId]['b111'].Media = { width: 300 }; - pbjs.adSupplyResponseHandler('bidId1'); - - sinon.assert.calledOnce(stubAddBidResponse); - - let bidPlacementCode = stubAddBidResponse.getCall(0).args[0]; - let bidResponse = stubAddBidResponse.getCall(0).args[1]; - expect(bidPlacementCode).to.equal('pc1'); - expect(bidResponse.getStatusCode()).to.equal(CONSTANTS.STATUS.NO_BID); - expect(bidResponse.bidderCode).to.equal('adsupply'); - - pbjs._bidsRequested.pop(); - bidmanager.addBidResponse.restore(); - }); - - it('Fill response', function () { - let stubAddBidResponse = sinon.stub(bidmanager, 'addBidResponse'); - // adapter needs to be called, in order for the stub to register. - new AdSupplyAdapter(); - - let clientId = 'g5d384afa-c050-4bac-b202-dab8fb06e381'; - //Zone property is not found - let bidderRequest = { - bidderCode: 'adsupply', - bids: [{ - placementCode: "pc1", - bidder: "adsupply", - bidId: 'bidId1', - params: { - clientId: clientId, - zoneId: 111, - siteId: '0ab16161-a1de-4683-8837-c420bd4387c0', - endpointUrl: 'engine.4dsply.com' - } - }] - }; - - pbjs._bidsRequested.push(bidderRequest); - - window[clientId] = window[clientId] || {}; - window[clientId]['b111'] = window[clientId]['b111'] || {}; - window[clientId]['b111'].Media = { Width: 300, Height: 250, Url: '/Redirect.engine', Ecpm: 0.0012 }; - pbjs.adSupplyResponseHandler('bidId1'); - - sinon.assert.calledOnce(stubAddBidResponse); - - let bidPlacementCode = stubAddBidResponse.getCall(0).args[0]; - let bidResponse = stubAddBidResponse.getCall(0).args[1]; - expect(bidPlacementCode).to.equal('pc1'); - expect(bidResponse.getStatusCode()).to.equal(CONSTANTS.STATUS.GOOD); - expect(bidResponse.bidderCode).to.equal('adsupply'); - - pbjs._bidsRequested.pop(); - bidmanager.addBidResponse.restore(); - }); -}); diff --git a/test/spec/adapters/beachfront_spec.js b/test/spec/adapters/beachfront_spec.js deleted file mode 100644 index 6401b6f5357..00000000000 --- a/test/spec/adapters/beachfront_spec.js +++ /dev/null @@ -1,133 +0,0 @@ -import { expect } from 'chai'; -import BeachfrontAdapter from 'src/adapters/beachfront'; -import bidmanager from 'src/bidmanager'; - -const ENDPOINT = '//reachms.bfmio.com/bid.json?exchange_id=11bc5dd5-7421-4dd8-c926-40fa653bec76'; - -const REQUEST = { - "width": 640, - "height": 480, - "bidId": "2a1444be20bb2c", - "bidder": "beachfront", - "bidderRequestId": "7101db09af0db2", - "params": { - "appId": "whatever", - "video": {}, - "placementCode": "video", - "sizes": [ - 640, 480 - ] - }, - "bids": [ - { - "bidFloor": 0.01, - "bidder": "beachfront", - "params": { - "appId": "11bc5dd5-7421-4dd8-c926-40fa653bec76", - "bidfloor": 0.01, - "dev": true - }, - "placementCode": "video", - "sizes": [640, 480], - "bidId": "2a1444be20bb2c", - "bidderRequestId": "7101db09af0db2", - "requestId": "979b659e-ecff-46b8-ae03-7251bae4b725" - } - ], - "requestId": "979b659e-ecff-46b8-ae03-7251bae4b725", -}; -var RESPONSE = { - "bidPrice": 5.00, - "url": "http://reachms.bfmio.com/getmu?aid=bid:19c4a196-fb21-4c81-9a1a-ecc5437a39da:0a47f4ce-d91f-48d0-bd1c-64fa2c196f13:2.90&dsp=58bf26882aba5e6ad608beda,0.612&i_type=pre" -}; - -describe('BeachfrontAdapter', () => { - - let adapter; - - beforeEach(() => adapter = BeachfrontAdapter.createNew()); - - describe('request function', () => { - let xhr; - let requests; - beforeEach(() => { - xhr = sinon.useFakeXMLHttpRequest(); - requests = []; - xhr.onCreate = request => requests.push(request); - }); - - afterEach(() => xhr.restore()); - - it('exists and is a function', () => { - expect(adapter.callBids).to.exist.and.to.be.a('function'); - }); - - it('requires parameters to make request', () => { - adapter.callBids({}); - expect(requests).to.be.empty; - }); - - it('sends bid request to ENDPOINT via POST', () => { - adapter.callBids(REQUEST); - expect(requests[0].url).to.equal(ENDPOINT); - expect(requests[0].method).to.equal('POST'); - }); - }); - - describe('response handler', () => { - - let server; - - beforeEach(() => { - server = sinon.fakeServer.create(); - sinon.stub(bidmanager, 'addBidResponse'); - }); - - afterEach(() => { - server.restore(); - bidmanager.addBidResponse.restore(); - }); - - it('registers bids', () => { - server.respondWith(JSON.stringify(RESPONSE)); - - adapter.callBids(REQUEST); - server.respond(); - sinon.assert.calledOnce(bidmanager.addBidResponse); - - const response = bidmanager.addBidResponse.firstCall.args[1]; - expect(response).to.have.property('statusMessage', 'Bid available'); - expect(response).to.have.property('cpm', 5.00); - }); - - it('handles nobid responses', () => { - server.respondWith(JSON.stringify({ - "bidPrice": 5.00 - })); - - adapter.callBids(REQUEST); - server.respond(); - sinon.assert.calledOnce(bidmanager.addBidResponse); - - const response = bidmanager.addBidResponse.firstCall.args[1]; - expect(response).to.have.property( - 'statusMessage', - 'Bid returned empty or error response' - ); - }); - - it('handles JSON.parse errors', () => { - server.respondWith(''); - - adapter.callBids(REQUEST); - server.respond(); - sinon.assert.calledOnce(bidmanager.addBidResponse); - - const response = bidmanager.addBidResponse.firstCall.args[1]; - expect(response).to.have.property( - 'statusMessage', - 'Bid returned empty or error response' - ); - }); - }); -}); diff --git a/test/spec/adapters/bidfluence_spec.js b/test/spec/adapters/bidfluence_spec.js deleted file mode 100644 index d6851f4fac2..00000000000 --- a/test/spec/adapters/bidfluence_spec.js +++ /dev/null @@ -1,74 +0,0 @@ -describe('Bidfluence Adapter', () => { - const expect = require('chai').expect; - const adapter = require('src/adapters/bidfluence'); - const bidmanager = require('src/bidmanager'); - - var REQUEST = { - bidderCode: "bidfluence", - sizes: [[300, 250]], - placementCode: "div-1", - bids: [{ - bidder: 'bidfluence', - params: { - pubId: "test", - adunitId: "test" - } - }] - }; - - var RESPONSE = { - ad: "ad-code", - cpm: 0.9, - width: 300, - height: 250, - placementCode: "div-1" - }; - - var NO_RESPONSE = { - ad: "ad-code", - cpm: 0, - width: 300, - height: 250, - placementCode: "div-1" - }; - - it('Should exist and be a function', function () { - expect($$PREBID_GLOBAL$$.bfPbjsCB).to.exist.and.to.be.a('function'); - }); - - it('Shoud push a valid bid', () => { - - var stubAddBidResponse = sinon.stub(bidmanager, "addBidResponse"); - pbjs._bidsRequested.push(REQUEST); - adapter(); - $$PREBID_GLOBAL$$.bfPbjsCB(RESPONSE); - - var bidPlacementCode1 = stubAddBidResponse.getCall(0).args[0]; - var bidObject1 = stubAddBidResponse.getCall(0).args[1]; - - expect(bidPlacementCode1).to.equal("div-1"); - expect(bidObject1.getStatusCode()).to.equal(1); - expect(bidObject1.bidderCode).to.equal('bidfluence'); - - stubAddBidResponse.restore(); - }); - - it('Shoud push an empty bid', () => { - - var stubAddBidResponse = sinon.stub(bidmanager, "addBidResponse"); - pbjs._bidsRequested.push(REQUEST); - adapter(); - - $$PREBID_GLOBAL$$.bfPbjsCB(NO_RESPONSE); - - var bidPlacementCode1 = stubAddBidResponse.getCall(0).args[0]; - var bidObject1 = stubAddBidResponse.getCall(0).args[1]; - - expect(bidPlacementCode1).to.equal("div-1"); - expect(bidObject1.getStatusCode()).to.equal(2); - expect(bidObject1.bidderCode).to.equal('bidfluence'); - - stubAddBidResponse.restore(); - - }); -}); diff --git a/test/spec/adapters/centro_spec.js b/test/spec/adapters/centro_spec.js deleted file mode 100644 index a3f186fad65..00000000000 --- a/test/spec/adapters/centro_spec.js +++ /dev/null @@ -1,230 +0,0 @@ -describe('centro adapter tests', function () { - var expect = require('chai').expect; - var assert = require('chai').assert; - var urlParse = require('url-parse'); - var querystringify = require('querystringify'); - - var adapter = require('src/adapters/centro'); - var bidmanager = require('src/bidmanager'); - var adLoader = require('src/adloader'); - var utils = require('src/utils'); - - window.pbjs = window.pbjs || {}; - if (typeof(pbjs)==="undefined"){ - var pbjs = window.pbjs; - } - - let stubLoadScript; - beforeEach(function () { - stubLoadScript = sinon.stub(adLoader, 'loadScript'); - }); - - afterEach(function () { - stubLoadScript.restore(); - }); - - var logErrorSpy; - beforeEach(function () { - logErrorSpy = sinon.spy(utils, 'logError'); - }); - - afterEach(function () { - logErrorSpy.restore(); - }); - - describe('creation of bid url', function () { - - if (typeof(pbjs._bidsRequested)==="undefined"){ - pbjs._bidsRequested = []; - } - - it('should fix parameter name', function () { - - var params = { - bidderCode: 'centro', - bids: [ - { - bidder: 'centro', - sizes: [[300, 250]], - params: { - unit: 28136, - page_url: 'http://test_url.ru' - }, - placementCode: 'div-gpt-ad-12345-1' - }, - { - bidder: 'centro', - sizes: [[728, 90]], - params: { - unit: 28137 - }, - placementCode: 'div-gpt-ad-12345-2' - }, - { - bidder: 'centro', - sizes: [[728, 90]], - params: {}, - placementCode: 'div-gpt-ad-12345-3' - } - ] - }; - - adapter().callBids(params); - var bidUrl1 = stubLoadScript.getCall(0).args[0]; - var bidUrl2 = stubLoadScript.getCall(1).args[0]; - - sinon.assert.calledWith(logErrorSpy, 'Bid has no unit', 'centro'); - sinon.assert.calledWith(stubLoadScript, bidUrl1); - - var parsedBidUrl = urlParse(bidUrl1); - var parsedBidUrlQueryString = querystringify.parse(parsedBidUrl.query); - var generatedCallback = 'window["adCentroHandler_28136300x250div-gpt-ad-12345-1"]'; - - expect(parsedBidUrl.hostname).to.equal('staging.brand-server.com'); - expect(parsedBidUrl.pathname).to.equal('/hb'); - - expect(parsedBidUrlQueryString).to.have.property('s').and.to.equal('28136'); - expect(parsedBidUrlQueryString).to.have.property('url').and.to.equal('http://test_url.ru'); - expect(parsedBidUrlQueryString).to.have.property('sz').and.to.equal('300x250'); - expect(parsedBidUrlQueryString).to.have.property('callback').and.to.equal(generatedCallback); - - sinon.assert.calledWith(stubLoadScript, bidUrl2); - - parsedBidUrl = urlParse(bidUrl2); - parsedBidUrlQueryString = querystringify.parse(parsedBidUrl.query); - generatedCallback = 'window["adCentroHandler_28137728x90div-gpt-ad-12345-2"]'; - - expect(parsedBidUrl.hostname).to.equal('t.brand-server.com'); - expect(parsedBidUrl.pathname).to.equal('/hb'); - - expect(parsedBidUrlQueryString).to.have.property('s').and.to.equal('28137'); - expect(parsedBidUrlQueryString).to.have.property('url').and.to.equal(location.href); - expect(parsedBidUrlQueryString).to.have.property('sz').and.to.equal('728x90'); - expect(parsedBidUrlQueryString).to.have.property('callback').and.to.equal(generatedCallback); - }); - - }); - - describe('handling of the callback response', function () { - if (typeof(pbjs._bidsReceived)==="undefined"){ - pbjs._bidsReceived = []; - } - if (typeof(pbjs._bidsRequested)==="undefined"){ - pbjs._bidsRequested = []; - } - if (typeof(pbjs._adsReceived)==="undefined"){ - pbjs._adsReceived = []; - } - - var params = { - bidderCode: 'centro', - bids: [ - { - bidder: 'centro', - sizes: [[300, 250]], - params: { - unit: 28136 - }, - placementCode: '/19968336/header-bid-tag-0' - }, - { - bidder: 'centro', - sizes: [[728, 90]], - params: { - unit: 111111 - }, - placementCode: '/19968336/header-bid-tag-1' - }, - { - bidder: 'centro', - sizes: [[728, 90]], - params: { - unit: 222222 - }, - placementCode: '/19968336/header-bid-tag-2' - }, - { - bidder: 'centro', - sizes: [[728, 90]], - params: { - unit: 333333 - }, - placementCode: '/19968336/header-bid-tag-3' - } - ] - }; - - it('callback function should exist', function () { - - adapter().callBids(params); - - expect(window['adCentroHandler_28136300x250%2F19968336%2Fheader-bid-tag-0']) - .to.exist.and.to.be.a('function'); - expect(window['adCentroHandler_111111728x90%2F19968336%2Fheader-bid-tag-1']) - .to.exist.and.to.be.a('function'); - }); - - it('bidmanager.addBidResponse should be called with correct arguments', function () { - - var stubAddBidResponse = sinon.stub(bidmanager, 'addBidResponse'); - - adapter().callBids(params); - - var adUnits = new Array(); - var unit = new Object(); - unit.bids = params.bids; - unit.code = '/19968336/header-bid-tag'; - unit.sizes=[[300,250],[728,90]]; - adUnits.push(unit); - - if (typeof(pbjs._bidsRequested)==="undefined"){ - pbjs._bidsRequested = [params]; - } - else{ - pbjs._bidsRequested.push(params); - } - - pbjs.adUnits = adUnits; - - var response = {"adTag":"
test content
","statusMessage":"Bid available","height":250,"_comment":"","value":0.2,"width":300,"sectionID":28136}; - var response2 = {"adTag":"","statusMessage":"No bid.","height":0,"value":0,"width":0,"sectionID":111111}; - var response3 = {"adTag":"","height":0,"value":0,"width":0,"sectionID":222222}; - var response4 = ''; - - window['adCentroHandler_28136300x250%2F19968336%2Fheader-bid-tag-0'](response); - window['adCentroHandler_111111728x90%2F19968336%2Fheader-bid-tag-1'](response2); - window['adCentroHandler_222222728x90%2F19968336%2Fheader-bid-tag-2'](response3); - window['adCentroHandler_333333728x90%2F19968336%2Fheader-bid-tag-3'](response4); - - var bidPlacementCode1 = stubAddBidResponse.getCall(0).args[0]; - var bidObject1 = stubAddBidResponse.getCall(0).args[1]; - var bidPlacementCode2 = stubAddBidResponse.getCall(1).args[0]; - var bidObject2 = stubAddBidResponse.getCall(1).args[1]; - var bidPlacementCode3 = stubAddBidResponse.getCall(2).args[0]; - var bidObject3 = stubAddBidResponse.getCall(2).args[1]; - var bidPlacementCode4 = stubAddBidResponse.getCall(3).args[0]; - var bidObject4 = stubAddBidResponse.getCall(3).args[1]; - - expect(logErrorSpy.getCall(0).args[0]).to.equal('Requested unit is 111111. No bid.'); - expect(logErrorSpy.getCall(1).args[0]).to.equal('Requested unit is 222222. Bid has missmatch format.'); - expect(logErrorSpy.getCall(2).args[0]).to.equal('Requested unit is 333333. Response has no bid.'); - - expect(bidPlacementCode1).to.equal('/19968336/header-bid-tag-0'); - expect(bidObject1.cpm).to.equal(0.2); - expect(bidObject1.ad).to.equal('
test content
'); - expect(bidObject1.width).to.equal(300); - expect(bidObject1.height).to.equal(250); - expect(bidObject1.getStatusCode()).to.equal(1); - expect(bidObject1.bidderCode).to.equal('centro'); - - expect(bidPlacementCode2).to.equal('/19968336/header-bid-tag-1'); - expect(bidObject2.getStatusCode()).to.equal(2); - expect(bidPlacementCode3).to.equal('/19968336/header-bid-tag-2'); - expect(bidObject3.getStatusCode()).to.equal(2); - expect(bidPlacementCode4).to.equal('/19968336/header-bid-tag-3'); - expect(bidObject4.getStatusCode()).to.equal(2); - - stubAddBidResponse.restore(); - }); - }); -}); diff --git a/test/spec/adapters/districtm_spec.js b/test/spec/adapters/districtm_spec.js deleted file mode 100644 index 4b457fe8d3a..00000000000 --- a/test/spec/adapters/districtm_spec.js +++ /dev/null @@ -1,293 +0,0 @@ -/** - * Created by stevealliance on 2016-11-15. - */ - - - -import {expect} from "chai"; -import {should} from "chai"; -import Adaptor from '../../../src/adapters/districtmDMX'; - -import adLoader from '../../../src/adloader'; - - - -var _each = function(obj, fn){ - for(var o in obj){ - fn(o, obj[o]); - } -} - -let districtm; -const PREBID_RESPONSE = function(){ - return { - result: { - cpm: '3.45', - callbackId: '1490bd6bdc59ce', - width: 300, - height: 250, - banner: 'html' - }, - callback_uid: '1490bd6bdc59ce' - }; -} -const PREBID_PARAMS = { - bidderCode: 'districtmDMX', - requestId: '5ccedbd5-86c1-436f-8649-964262461eac', - bidderRequestId: '1490bd6bdc59ce', - start: new Date().getTime(), - bids: [{ - bidder: 'districtmDMX', - bidId: '84ab500420319d', - bidderRequestId: '1490bd6bdc59ce', - requestId: '5ccedbd5-86c1-436f-8649-964262461eac', - placementCode: 'golden', - params: { - placement: 109801, - floor: '1.00' - }, - sizes: [[300, 250], [300, 600]] - }] -}; - -function resetDm() { - window.hb_dmx_res = undefined; -} - -function activated() { - window.hb_dmx_res = { - ssp: {}, - bh(){ - - }, - auction: { - fixSize(s){ - let size; - if (!Array.isArray(s[0])) { - size = [s[0] + 'x' + s[1]]; - } else { - size = s.map(ss => { - return ss[0] + 'x' + ss[1]; - }) - } - - return size; - - }, - - run(a, b, c){ - - } - } - } -} - - -function definitions(){ - districtm.callBids({ - bidderCode: 'districtmDMX', - bids: [ - { - bidder: 'districtmDMX', - adUnitCode: 'golden', - sizes: [[728, 90]], - params: { - siteId: '101000' - } - }, - { - bidder: 'districtmDMX', - adUnitCode: 'stevealliance', - sizes: [[300, 250]], - params: { - siteId: '101000' - } - } - ] - }); -} -describe('DistrictM adapter test', () => { - - - describe('File loading', ()=>{ - let districtm; - afterEach(()=>{ - - districtm = new Adaptor(); - adLoader.loadScript(districtm.districtUrl, function(){}); - - }) - - it('For loading file ', ()=>{ - expect(!window.hb_dmx_res).to.equal(true); - }) - - - }) - - - describe('check for library do exists', ()=>{ - it('library was not loaded', ()=>{ - - expect(!window.hb_dmx_res).to.equal(true); - }) - - it('library is now available', ()=>{ - activated(); - - expect(!!window.hb_dmx_res).to.equal(true); - - }) - }) - - - describe('Check if size get clean', ()=>{ - beforeEach(()=>{ - activated(); - }) - it('size clean up using fixe size', ()=>{ - activated(); - - expect(window.hb_dmx_res.auction.fixSize([728, 90])[0]).to.equal(['728x90'][0]); - expect(window.hb_dmx_res.auction.fixSize([[300, 250], [300,600]]).toString()).to.equal(['300x250', '300x600'].toString()); - - }) - }) - - describe('Check call bids return no errors', ()=>{ - let districtm; - beforeEach(()=>{ - districtm = new Adaptor(); - }); - it('check value push using cal bids', ()=>{ - let obj = districtm.callBids(PREBID_PARAMS); - obj.should.have.property('bidderCode'); - obj.should.have.property('requestId'); - obj.should.have.property('bidderRequestId'); - obj.should.have.property('start'); - obj.should.have.property('bids'); - - }) - it('check if value got pass correctly for DM params', ()=>{ - let dm = districtm.callBids(PREBID_PARAMS).bids.map( bid => bid); - dm.forEach( a =>{ - a.should.have.property('bidder'); - a.should.have.property('requestId'); - a.should.have.property('bidderRequestId'); - a.should.have.property('placementCode'); - a.should.have.property('params'); - a.should.have.property('sizes'); - expect(a.bidder).to.equal('districtmDMX'); - expect(a.placementCode).to.equal('golden'); - expect(a.params.placement).to.equal(109801); - }) - - - }) - }) - - describe('Run prebid definitions !', ()=>{ - let districtm; - beforeEach(()=>{ - districtm = new Adaptor(); - }) - - it('Run and return send bids', ()=>{ - let sendBids = districtm.sendBids(PREBID_PARAMS); - sendBids.forEach(sb =>{ - - expect(sb.sizes.toString()).to.equal([[300, 250], [300, 600]].toString()); - }) - - }) - - - }) - - describe('HandlerRes function test', ()=>{ - let districtm; - - beforeEach(()=>{ - districtm = new Adaptor(); - }) - - it('it\'s now time to play with the response ...', ()=>{ - let result = districtm.handlerRes(PREBID_RESPONSE(), PREBID_PARAMS); - _each(result, function(k, v){ - - }) - - - expect(result.cpm).to.equal('3.45'); - expect(result.width).to.equal(300); - expect(result.height).to.equal(250); - expect(result.ad).to.equal('html'); - - - - } ) - it('it\'s now time to play with the response failure...', ()=>{ - let result = districtm.handlerRes({result:{cpm:0}}, PREBID_PARAMS); - - result.should.have.property('bidderCode'); - - - } ) - - }) - - describe('look at the adloader', ()=>{ - let districtm; - beforeEach(()=>{ - districtm = new Adaptor(); - sinon.stub(adLoader, "loadScript"); - }) - - it('Verify districtm library is downloaded if nessesary', () => { - resetDm(); - districtm.callBids(PREBID_PARAMS); - let libraryLoadCall = adLoader.loadScript.firstCall.args[0]; - let callback = adLoader.loadScript.firstCall.args[1]; - expect(libraryLoadCall).to.equal('http://prebid.districtm.ca/lib.js'); - expect(callback).to.be.a('function'); - - - }); - - afterEach(()=>{ - adLoader.loadScript.restore(); - }) - - - - - }); - describe('run send bid from within !!!', ()=> { - beforeEach(()=> { - districtm = new Adaptor(); - sinon.stub(districtm, 'sendBids'); - }) - - it('last test on send bids', ()=>{ - resetDm(); - districtm.sendBids(PREBID_PARAMS); - expect(districtm.sendBids.calledOnce).to.be.true; - expect(districtm.sendBids.firstCall.args[0]).to.be.a('object'); - - - }); - - afterEach(()=> { - districtm.sendBids.restore(); - }) - - }); - - - - - - - -}); - diff --git a/test/spec/adapters/huddledmasses_spec.js b/test/spec/adapters/huddledmasses_spec.js deleted file mode 100644 index 434ae58cd58..00000000000 --- a/test/spec/adapters/huddledmasses_spec.js +++ /dev/null @@ -1,130 +0,0 @@ -import { expect } from 'chai'; -import Adapter from '../../../src/adapters/huddledmasses'; -import adapterManager from 'src/adaptermanager'; -import bidManager from 'src/bidmanager'; -import CONSTANTS from 'src/constants.json'; - -describe('HuddledMasses adapter tests', function () { - - let sandbox; - const adUnit = { - code: 'huddledmasses', - sizes: [[300, 250], [300,600]], - bids: [{ - bidder: 'huddledmasses', - params: { - placement_id: 0 - } - }] - }; - - const response = { - ad_id: 15, - adm: "
Bid Response
", - cpm: 0.712, - deal: "5e1f0a8f2aa1", - width: 300, - height: 250 - }; - - beforeEach(() => { - sandbox = sinon.sandbox.create(); - }); - - afterEach(() => { - sandbox.restore(); - }); - - describe('HuddledMasses callBids validation', () => { - - let bids, - server; - - beforeEach(() => { - bids = []; - server = sinon.fakeServer.create(); - sandbox.stub(bidManager, 'addBidResponse', (elemId, bid) => { - bids.push(bid); - }); - }); - - afterEach(() => { - server.restore(); - }); - - let adapter = adapterManager.bidderRegistry['huddledmasses']; - - it('Valid bid-request', () => { - sandbox.stub(adapter, 'callBids'); - adapterManager.callBids({ - adUnits: [clone(adUnit)] - }); - - let bidderRequest = adapter.callBids.getCall(0).args[0]; - - expect(bidderRequest).to.have.property('bids') - .that.is.an('array') - .with.lengthOf(1); - - expect(bidderRequest).to.have.deep.property('bids[0]') - .to.have.property('bidder', 'huddledmasses'); - - expect(bidderRequest).to.have.deep.property('bids[0]') - .with.property('sizes') - .that.is.an('array') - .with.lengthOf(2) - .that.deep.equals(adUnit.sizes); - expect(bidderRequest).to.have.deep.property('bids[0]') - .with.property('params') - .to.have.property('placement_id', 0); - }); - - it('Valid bid-response', ()=>{ - server.respondWith(JSON.stringify( - response - )); - adapterManager.callBids({ - adUnits: [clone(adUnit)] - }); - server.respond(); - - expect(bids).to.be.lengthOf(1); - expect(bids[0].getStatusCode()).to.equal(CONSTANTS.STATUS.GOOD); - expect(bids[0].bidderCode).to.equal("huddledmasses"); - expect(bids[0].width).to.equal(300); - expect(bids[0].height).to.equal(250); - expect(bids[0].cpm).to.equal(0.712); - expect(bids[0].dealId).to.equal("5e1f0a8f2aa1"); - }); - }); - - describe('MAS mapping / ordering', () => { - - let masSizeOrdering = Adapter.masSizeOrdering; - - it('should not include values without a proper mapping', () => { - let ordering = masSizeOrdering([[320, 50], [42, 42], [300, 250], [640, 480], [0, 0]]); - expect(ordering).to.deep.equal([15, 43, 65]); - }); - - it('should sort values without any MAS priority sizes in regular ascending order', () => { - let ordering = masSizeOrdering([[320, 50], [640, 480], [200, 600]]); - expect(ordering).to.deep.equal([43, 65, 119]); - }); - - it('should sort MAS priority sizes in the proper order w/ rest ascending', () => { - let ordering = masSizeOrdering([[320, 50], [640, 480], [300, 250], [200, 600]]); - expect(ordering).to.deep.equal([15, 43, 65, 119]); - - ordering = masSizeOrdering([[320, 50], [300, 250], [640, 480], [200, 600], [728, 90]]); - expect(ordering).to.deep.equal([15, 2, 43, 65, 119]); - - ordering = masSizeOrdering([ [320, 50], [640, 480], [200, 600], [728, 90]]); - expect(ordering).to.deep.equal([2, 43, 65, 119]); - }) - }); -}); - -function clone(obj) { - return JSON.parse(JSON.stringify(obj)); -} \ No newline at end of file diff --git a/test/spec/adapters/indexExchange_request_spec.js b/test/spec/adapters/indexExchange_request_spec.js deleted file mode 100644 index 5b41bc5cfd9..00000000000 --- a/test/spec/adapters/indexExchange_request_spec.js +++ /dev/null @@ -1,466 +0,0 @@ -import Adapter from '../../../src/adapters/indexExchange'; -import bidManager from '../../../src/bidmanager'; -import adLoader from '../../../src/adloader'; - -var assert = require('chai').assert; -var IndexUtils = require('../../helpers/index_adapter_utils.js'); -var HeaderTagRequest = '/cygnus'; -var SlotThreshold = 20; -var ADAPTER_CODE = 'indexExchange'; - -window.pbjs = window.pbjs || {}; - -describe('indexExchange adapter - Request', function () { - let adapter; - let sandbox; - - beforeEach( function() { - window._IndexRequestData = {}; - _IndexRequestData.impIDToSlotID = {}; - _IndexRequestData.reqOptions = {}; - _IndexRequestData.targetIDToResp = {}; - window.cygnus_index_args = {}; - - adapter = new Adapter(); - sandbox = sinon.sandbox.create(); - sandbox.stub(adLoader, 'loadScript'); - }); - - afterEach( function() { - sandbox.restore(); - }); - - it('test_prebid_indexAdapter_parameter_x3: prebid sends AS request -> x3 parameter does not exist in the request', function () { - var configuredBids = IndexUtils.createBidSlots(); - adapter.callBids({ bids: configuredBids }); - - assert.notInclude(adLoader.loadScript.firstCall.args[0], 'x3=', 'x3 parameter is not in AS request'); - }); - - it('test_prebid_indexAdapter_request_1_1: single slot with single size -> single request object for the slot', function () { - var configuredBids = IndexUtils.createBidSlots(); - adapter.callBids({ bids: configuredBids }); - - assert.isTrue(adLoader.loadScript.called, "loadScript get request"); - - assert.include(adLoader.loadScript.firstCall.args[0], HeaderTagRequest, "request is headertag request"); - - var requestJSON = IndexUtils.parseIndexRequest(adLoader.loadScript.firstCall.args[0]); - assert.isNotNull( requestJSON.r.imp, "headertag request include impression object" ); - - var impressionObj = requestJSON.r.imp; - - var expandedBids = configuredBids.map(bid => IndexUtils.expandSizes(bid)) - var sidMatched = IndexUtils.matchBidsOnSID(expandedBids, impressionObj); - for ( var i = 0; i < sidMatched.matched.length; i++) { - var pair = sidMatched.matched[i]; - - assert.equal(pair.sent.banner.w, pair.configured.size[0], "request " + pair.name + " width is set to " + pair.configured.size[0]); - assert.equal(pair.sent.banner.h, pair.configured.size[1], "request " + pair.name + " width is set to " + pair.configured.size[1]); - assert.equal(pair.sent.ext.siteID, pair.configured.params.siteID, "request " + pair.name + " siteID is set to " + pair.configured.params.siteID); - } - - assert.equal( sidMatched.unmatched.configured.length, 0, "All configured bids are in impression Obj"); - assert.equal( sidMatched.unmatched.sent.length, 0, "All bids in impression object are from configured bids"); - assert.isString( requestJSON.r.id, "ID is string"); - }); - - it('test_prebid_indexAdapter_request_1_1: single slot with single size -> single request object for the slot', function () { - var configuredBids = IndexUtils.createBidSlots(); - adapter.callBids({ bids: configuredBids }); - - assert.isTrue(adLoader.loadScript.called, "loadScript get request"); - - assert.include(adLoader.loadScript.firstCall.args[0], HeaderTagRequest, "request is headertag request"); - - var requestJSON = IndexUtils.parseIndexRequest(adLoader.loadScript.firstCall.args[0]); - assert.isNotNull( requestJSON.r.imp, "headertag request include impression object" ); - - var impressionObj = requestJSON.r.imp; - - var expandedBids = configuredBids.map(bid => IndexUtils.expandSizes(bid)) - var sidMatched = IndexUtils.matchBidsOnSID(expandedBids, impressionObj); - for ( var i = 0; i < sidMatched.matched.length; i++) { - var pair = sidMatched.matched[i]; - - assert.equal(pair.sent.banner.w, pair.configured.size[0], "request " + pair.name + " width is set to " + pair.configured.size[0]); - assert.equal(pair.sent.banner.h, pair.configured.size[1], "request " + pair.name + " width is set to " + pair.configured.size[1]); - assert.equal(pair.sent.ext.siteID, pair.configured.params.siteID, "request " + pair.name + " siteID is set to " + pair.configured.params.siteID); - } - - assert.equal( sidMatched.unmatched.configured.length, 0, "All configured bids are in impression Obj"); - assert.equal( sidMatched.unmatched.sent.length, 0, "All bids in impression object are from configured bids"); - - - }); - - it('test_prebid_indexAdapter_request_1_2: single slot with unsupported single size -> indexExchange does not participate in auction', function () { - var configuredBids = [ - IndexUtils.createBidSlot( IndexUtils.DefaultPlacementCodePrefix, "slot_1", [ IndexUtils.unsupportedSizes[0] ] ) - ]; - adapter.callBids({ bids: configuredBids }); - - assert.isUndefined( adLoader.loadScript.firstCall.args[0], "no request made to AS"); - }); - - - it('test_prebid_indexAdapter_request_2_1: single slot with all supported multiple sizes -> multiple request objects for the slot', function () { - var configuredBids = IndexUtils.createBidSlots(1, 5); - adapter.callBids({ bids: configuredBids }); - - assert.isTrue(adLoader.loadScript.called, "loadScript get request"); - assert.include(adLoader.loadScript.firstCall.args[0], HeaderTagRequest, "request is headertag request"); - - var requestJSON = IndexUtils.parseIndexRequest(adLoader.loadScript.firstCall.args[0]); - assert.isNotNull( requestJSON.r.imp, "headertag request include impression object" ); - - var impressionObj = requestJSON.r.imp; - - var expandedBids = configuredBids.map(bid => IndexUtils.expandSizes(bid)) - var sidMatched = IndexUtils.matchBidsOnSID(expandedBids, impressionObj); - for ( var i = 0; i < sidMatched.matched.length; i++) { - var pair = sidMatched.matched[i]; - - assert.equal(pair.sent.banner.w, pair.configured.size[0], "request " + pair.name + " width is set to " + pair.configured.size[0]); - assert.equal(pair.sent.banner.h, pair.configured.size[1], "request " + pair.name + " width is set to " + pair.configured.size[1]); - assert.equal(pair.sent.ext.siteID, pair.configured.params.siteID, "request " + pair.name + " siteID is set to " + pair.configured.params.siteID); - } - - assert.equal( sidMatched.unmatched.configured.length, 0, "All configured bids are in impression Obj"); - assert.equal( sidMatched.unmatched.sent.length, 0, "All bids in impression object are from configured bids"); - }); - - it('test_prebid_indexAdapter_request_2_2: single slot with all unsupported multiple sizes -> no request objects for the slot', function () { - var isSetExpectedBidsCountCalled = false; - - var configuredBids = [ - IndexUtils.createBidSlot( IndexUtils.DefaultPlacementCodePrefix, "slot_1", [ IndexUtils.unsupportedSizes[0], IndexUtils.unsupportedSizes[1], IndexUtils.unsupportedSizes[2] ] ) - ]; - adapter.callBids({ bids: configuredBids }); - - assert.isUndefined( adLoader.loadScript.firstCall.args[0], "no request made to AS"); - }); - - it('test_prebid_indexAdapter_request_2_3: single slot with supported, unsupportrd, supported sizes -> only the supported size request objects for the slot', function () { - var unsupportedSize = IndexUtils.unsupportedSizes[0]; - var configuredBids = [ - IndexUtils.createBidSlot( IndexUtils.DefaultPlacementCodePrefix, "slot_1", [ IndexUtils.supportedSizes[0], unsupportedSize, IndexUtils.supportedSizes[1] ] ) - ]; - adapter.callBids({ bids: configuredBids }); - - assert.isTrue(adLoader.loadScript.called, "loadScript get request"); - assert.include(adLoader.loadScript.firstCall.args[0], HeaderTagRequest, "request is headertag request"); - - var requestJSON = IndexUtils.parseIndexRequest(adLoader.loadScript.firstCall.args[0]); - assert.isNotNull( requestJSON.r.imp, "headertag request include impression object" ); - - var impressionObj = requestJSON.r.imp; - var expandedBids = configuredBids.map(bid => IndexUtils.expandSizes(bid)) - - var sidMatched = IndexUtils.matchBidsOnSize(expandedBids, impressionObj); - for ( var i = 0; i < sidMatched.matched.length; i++) { - var pair = sidMatched.matched[i]; - assert.equal(pair.sent.banner.w, pair.configured.size[0], "request " + pair.name + " width is set to " + pair.configured.size[0]); - assert.equal(pair.sent.banner.h, pair.configured.size[1], "request " + pair.name + " width is set to " + pair.configured.size[1]); - assert.equal(pair.sent.ext.siteID, pair.configured.params.siteID, "request " + pair.name + " siteID is set to " + pair.configured.params.siteID); - } - - - assert.equal( sidMatched.unmatched.sent.length, 0, "All bids in impression object are from configured bids"); - - assert.equal( sidMatched.unmatched.configured.length, 1, "1 configured bid is not in impression Obj"); - assert.equal( sidMatched.unmatched.configured[0].size, unsupportedSize, "configured bid not in impression obj size width is" + JSON.stringify(unsupportedSize) ); - }); - - it('test_prebid_indexAdapter_request_2_4: single slot with unsupported, supportrd, unsupported sizes -> only the supported size request objects for the slot', function () { - var unsupportedSize1 = IndexUtils.unsupportedSizes[0]; - var unsupportedSize2 = IndexUtils.unsupportedSizes[1]; - var configuredBids = [ - IndexUtils.createBidSlot( IndexUtils.DefaultPlacementCodePrefix, "slot_1", [ unsupportedSize1, IndexUtils.supportedSizes[1], unsupportedSize2 ] ) - ]; - adapter.callBids({ bids: configuredBids }); - - assert.isTrue(adLoader.loadScript.called, "loadScript get request"); - assert.include(adLoader.loadScript.firstCall.args[0], HeaderTagRequest, "request is headertag request"); - - var requestJSON = IndexUtils.parseIndexRequest(adLoader.loadScript.firstCall.args[0]); - assert.isNotNull( requestJSON.r.imp, "headertag request include impression object" ); - - var impressionObj = requestJSON.r.imp; - var expandedBids = configuredBids.map(bid => IndexUtils.expandSizes(bid)) - - var sidMatched = IndexUtils.matchBidsOnSize(expandedBids, impressionObj); - for ( var i = 0; i < sidMatched.matched.length; i++) { - var pair = sidMatched.matched[i]; - - assert.equal(pair.sent.banner.w, pair.configured.size[0], "request " + pair.name + " width is set to " + pair.configured.size[0]); - assert.equal(pair.sent.banner.h, pair.configured.size[1], "request " + pair.name + " width is set to " + pair.configured.size[1]); - assert.equal(pair.sent.ext.siteID, pair.configured.params.siteID, "request " + pair.name + " siteID is set to " + pair.configured.params.siteID); - } - - - assert.equal( sidMatched.unmatched.sent.length, 0, "All bids in impression object are from configured bids"); - - assert.equal( sidMatched.unmatched.configured.length, 2, "2 configured bid is not in impression Obj"); - assert.equal( sidMatched.unmatched.configured[0].size, unsupportedSize1, "configured bid not in impression obj size width is" + JSON.stringify(unsupportedSize1) ); - assert.equal( sidMatched.unmatched.configured[1].size, unsupportedSize2, "configured bid not in impression obj size width is" + JSON.stringify(unsupportedSize2) ); - }); - - it('test_prebid_indexAdapter_request_3: multiple slots with single size below allowed slot threshold -> request for all the slots', function () { - var configuredBids = IndexUtils.createBidSlots(10); - adapter.callBids({ bids: configuredBids }); - - assert.isTrue(adLoader.loadScript.called, "loadScript get request"); - assert.include(adLoader.loadScript.firstCall.args[0], HeaderTagRequest, "request is headertag request"); - - var requestJSON = IndexUtils.parseIndexRequest(adLoader.loadScript.firstCall.args[0]); - assert.isNotNull( requestJSON.r.imp, "headertag request include impression object" ); - - var impressionObj = requestJSON.r.imp; - - var expandedBids = configuredBids.map(bid => IndexUtils.expandSizes(bid)) - var sidMatched = IndexUtils.matchBidsOnSID(expandedBids, impressionObj); - for ( var i = 0; i < sidMatched.matched.length; i++) { - var pair = sidMatched.matched[i]; - - assert.equal(pair.sent.banner.w, pair.configured.size[0], "request " + pair.name + " width is set to " + pair.configured.size[0]); - assert.equal(pair.sent.banner.h, pair.configured.size[1], "request " + pair.name + " width is set to " + pair.configured.size[1]); - assert.equal(pair.sent.ext.siteID, pair.configured.params.siteID, "request " + pair.name + " siteID is set to " + pair.configured.params.siteID); - } - - assert.equal( sidMatched.unmatched.configured.length, 0, "All configured bids are in impression Obj"); - assert.equal( sidMatched.unmatched.sent.length, 0, "All bids in impression object are from configured bids"); - }); - - it('test_prebid_indexAdapter_request_4: multiple slots with single size at exact allowed slot threshold -> request for all the slots', function () { - var configuredBids = IndexUtils.createBidSlots(SlotThreshold); - adapter.callBids({ bids: configuredBids }); - - assert.isTrue(adLoader.loadScript.called, "loadScript get request"); - assert.include(adLoader.loadScript.firstCall.args[0], HeaderTagRequest, "request is headertag request"); - - var requestJSON = IndexUtils.parseIndexRequest(adLoader.loadScript.firstCall.args[0]); - assert.isNotNull( requestJSON.r.imp, "headertag request include impression object" ); - - var impressionObj = requestJSON.r.imp; - - var expandedBids = configuredBids.map(bid => IndexUtils.expandSizes(bid)) - var sidMatched = IndexUtils.matchBidsOnSID(expandedBids, impressionObj); - for ( var i = 0; i < sidMatched.matched.length; i++) { - var pair = sidMatched.matched[i]; - - assert.equal(pair.sent.banner.w, pair.configured.size[0], "request " + pair.name + " width is set to " + pair.configured.size[0]); - assert.equal(pair.sent.banner.h, pair.configured.size[1], "request " + pair.name + " width is set to " + pair.configured.size[1]); - assert.equal(pair.sent.ext.siteID, pair.configured.params.siteID, "request " + pair.name + " siteID is set to " + pair.configured.params.siteID); - } - - assert.equal( sidMatched.unmatched.configured.length, 0, "All configured bids are in impression Obj"); - assert.equal( sidMatched.unmatched.sent.length, 0, "All bids in impression object are from configured bids"); - }); - - it('test_prebid_indexAdapter_request_5: multiple slots with single size exceed allowed slot threshold -> request for all the slots', function () { - var requestSlotNumber = SlotThreshold+1; - var configuredBids = IndexUtils.createBidSlots(requestSlotNumber); - adapter.callBids({ bids: configuredBids }); - - assert.isTrue(adLoader.loadScript.called, "loadScript get request"); - assert.include(adLoader.loadScript.firstCall.args[0], HeaderTagRequest, "request is headertag request"); - - var requestJSON = IndexUtils.parseIndexRequest(adLoader.loadScript.firstCall.args[0]); - assert.isNotNull( requestJSON.r.imp, "headertag request include impression object" ); - - var impressionObj = requestJSON.r.imp; - - var expandedBids = configuredBids.map(bid => IndexUtils.expandSizes(bid)) - var sidMatched = IndexUtils.matchBidsOnSID(expandedBids, impressionObj); - - for ( var i = 0; i < sidMatched.matched.length; i++) { - var pair = sidMatched.matched[i]; - - assert.equal(pair.sent.banner.w, pair.configured.size[0], "request " + pair.name + " width is set to " + pair.configured.size[0]); - assert.equal(pair.sent.banner.h, pair.configured.size[1], "request " + pair.name + " width is set to " + pair.configured.size[1]); - assert.equal(pair.sent.ext.siteID, pair.configured.params.siteID, "request " + pair.name + " siteID is set to " + pair.configured.params.siteID); - } - - assert.equal( sidMatched.unmatched.configured.length, 0, "All configured bids are in impression Obj"); - assert.equal( sidMatched.unmatched.sent.length, 0, "All bids in impression object are from configured bids"); - }); - - - it('test_prebid_indexAdapter_request_6: threshold valid + non valid which exceeds threshold -> 1 Ad Server request with supported sizes only', function () { - var unsupportedSizeCount = 1; - var requestSlotNumber = SlotThreshold; - var configuredBids = IndexUtils.createBidSlots(requestSlotNumber); - // add additional unsupported sized slot - var invalidSlotPlacement = IndexUtils.DefaultPlacementCodePrefix + 'invalid'; - var invalidSlotID = 'slot-invalid'; - configuredBids.push( IndexUtils.createBidSlot( invalidSlotPlacement, invalidSlotID, [ IndexUtils.unsupportedSizes[0] ] ) ); - - adapter.callBids({ bids: configuredBids }); - - assert.isTrue(adLoader.loadScript.called, "loadScript get request"); - assert.include(adLoader.loadScript.firstCall.args[0], HeaderTagRequest, "request is headertag request"); - - var requestJSON = IndexUtils.parseIndexRequest(adLoader.loadScript.firstCall.args[0]); - assert.isNotNull( requestJSON.r.imp, "headertag request include impression object" ); - - var impressionObj = requestJSON.r.imp; - - var expandedBids = configuredBids.map(bid => IndexUtils.expandSizes(bid)) - var sidMatched = IndexUtils.matchBidsOnSID(expandedBids, impressionObj); - - for ( var i = 0; i < sidMatched.matched.length; i++) { - var pair = sidMatched.matched[i]; - - assert.equal(pair.sent.banner.w, pair.configured.size[0], "request " + pair.name + " width is set to " + pair.configured.size[0]); - assert.equal(pair.sent.banner.h, pair.configured.size[1], "request " + pair.name + " width is set to " + pair.configured.size[1]); - assert.equal(pair.sent.ext.siteID, pair.configured.params.siteID, "request " + pair.name + " siteID is set to " + pair.configured.params.siteID); - } - - assert.equal( sidMatched.unmatched.configured.length, unsupportedSizeCount, unsupportedSizeCount + " of configured bids is missing in impression Obj"); - assert.equal( sidMatched.unmatched.configured[0].placementCode, invalidSlotPlacement, "missing slot's placement code is " + invalidSlotPlacement); - assert.equal( sidMatched.unmatched.configured[0].params.id, invalidSlotID, "missing slot's slotID is " + invalidSlotID); - - assert.equal( sidMatched.unmatched.sent.length, 0, "All bids in impression object are from configured bids"); - }); - - it('test_prebid_indexAdapter_request_7: multiple sizes with slots that exceeds max threshold requests -> 1 Ad Server request with supported sizes only', function () { - var requestSlotNumber = SlotThreshold; - var requestSizeNumber = 2; - var configuredBids = IndexUtils.createBidSlots(requestSlotNumber, requestSizeNumber ); - adapter.callBids({ bids: configuredBids }); - - assert.isTrue(adLoader.loadScript.called, "loadScript get request"); - assert.include(adLoader.loadScript.firstCall.args[0], HeaderTagRequest, "request is headertag request"); - - var requestJSON = IndexUtils.parseIndexRequest(adLoader.loadScript.firstCall.args[0]); - assert.isNotNull( requestJSON.r.imp, "headertag request include impression object" ); - - var impressionObj = requestJSON.r.imp; - - var expandedBids = configuredBids.map(bid => IndexUtils.expandSizes(bid)) - var sidMatched = IndexUtils.matchBidsOnSID(expandedBids, impressionObj); - - assert.equal( sidMatched.matched.length, requestSlotNumber * requestSizeNumber, 'All slots each with multiple sizes are in AS request'); - for ( var i = 0; i < sidMatched.matched.length; i++) { - var pair = sidMatched.matched[i]; - assert.equal(pair.sent.banner.w, pair.configured.size[0], "request " + pair.name + " width is set to " + pair.configured.size[0]); - assert.equal(pair.sent.banner.h, pair.configured.size[1], "request " + pair.name + " width is set to " + pair.configured.size[1]); - assert.equal(pair.sent.ext.siteID, pair.configured.params.siteID, "request " + pair.name + " siteID is set to " + pair.configured.params.siteID); - } - - assert.equal( sidMatched.unmatched.configured.length, 0, "All configured bids are in impression Obj"); - assert.equal( sidMatched.unmatched.sent.length, 0, "All bids in impression object are from configured bids"); - }); - - it('test_prebid_indexAdapter_request_sizeID_1: 1 prebid size slot, 1 index slot with size -> one slot in AS request 1 no size ID', function () { - var slotID = 52; - var slotSizes = IndexUtils.supportedSizes[0]; - - var configuredBids = [ - IndexUtils.createBidSlot( IndexUtils.DefaultPlacementCodePrefix, slotID, [ slotSizes ], { slotSize : slotSizes } ) - ]; - - adapter.callBids({ bids: configuredBids }); - - assert.isTrue(adLoader.loadScript.called, "loadScript get request"); - - assert.include(adLoader.loadScript.firstCall.args[0], HeaderTagRequest, "request is headertag request"); - - var requestJSON = IndexUtils.parseIndexRequest(adLoader.loadScript.firstCall.args[0]); - assert.isNotNull( requestJSON.r.imp, "headertag request include impression object" ); - - var impressionObj = requestJSON.r.imp; - - assert.equal(impressionObj.length, 1, "1 slot is made in the request" ); - assert.equal(impressionObj[0].banner.w, slotSizes[0], "the width made in the request matches with request: " + slotSizes[0] ); - assert.equal(impressionObj[0].banner.h, slotSizes[1], "the height made in the request matches with request: " + slotSizes[1] ); - assert.equal(impressionObj[0].ext.sid, slotID, "slotID in the request matches with configuration: " + slotID ); - assert.equal(impressionObj[0].ext.siteID, IndexUtils.DefaultSiteID, "siteID in the request matches with request: " + IndexUtils.DefaultSiteID ); - }); - - it('test_prebid_indexAdapter_request_sizeID_2: multiple prebid size slot, 1 index slot with size -> one slot in AS request 1 no size ID', function () { - var slotID = 52; - var slotSizes = IndexUtils.supportedSizes[0]; - - var configuredBids = [ - IndexUtils.createBidSlot( IndexUtils.DefaultPlacementCodePrefix, slotID, [ slotSizes, IndexUtils.supportedSizes[1] ], { slotSize : slotSizes } ) - ]; - - adapter.callBids({ bids: configuredBids }); - - assert.isTrue(adLoader.loadScript.called, "loadScript get request"); - - assert.include(adLoader.loadScript.firstCall.args[0], HeaderTagRequest, "request is headertag request"); - - var requestJSON = IndexUtils.parseIndexRequest(adLoader.loadScript.firstCall.args[0]); - assert.isNotNull( requestJSON.r.imp, "headertag request include impression object" ); - - var impressionObj = requestJSON.r.imp; - - assert.equal(impressionObj.length, 1, "1 slot is made in the request" ); - assert.equal(impressionObj[0].banner.w, slotSizes[0], "the width made in the request matches with request: " + slotSizes[0] ); - assert.equal(impressionObj[0].banner.h, slotSizes[1], "the height made in the request matches with request: " + slotSizes[1] ); - assert.equal(impressionObj[0].ext.sid, slotID, "slotID in the request matches with configuration: " + slotID ); - assert.equal(impressionObj[0].ext.siteID, IndexUtils.DefaultSiteID, "siteID in the request matches with request: " + IndexUtils.DefaultSiteID ); - }); - - it('test_prebid_indexAdapter_request_sizeID_3: multiple prebid size slot, index slots with size for all prebid slots -> all size in AS request, no size ID', function () { - var slotID_1 = 52; - var slotID_2 = 53; - var slotSizes_1 = IndexUtils.supportedSizes[0]; - var slotSizes_2 = IndexUtils.supportedSizes[1]; - - var configuredBids = [ - IndexUtils.createBidSlot( IndexUtils.DefaultPlacementCodePrefix, slotID_1, [ slotSizes_1, slotSizes_2 ], { slotSize : slotSizes_1 } ), - IndexUtils.createBidSlot( IndexUtils.DefaultPlacementCodePrefix, slotID_2, [ slotSizes_1, slotSizes_2 ], { slotSize : slotSizes_2 } ) - ]; - - adapter.callBids({ bids: configuredBids }); - - assert.isTrue(adLoader.loadScript.called, "loadScript get request"); - - assert.include(adLoader.loadScript.firstCall.args[0], HeaderTagRequest, "request is headertag request"); - - var requestJSON = IndexUtils.parseIndexRequest(adLoader.loadScript.firstCall.args[0]); - assert.isNotNull( requestJSON.r.imp, "headertag request include impression object" ); - - var impressionObj = requestJSON.r.imp; - assert.equal(impressionObj.length, 2, "2 slot is made in the request" ); - assert.equal(impressionObj[0].banner.w, slotSizes_1[0], "the width made in the request matches with request: " + slotSizes_1[0] ); - assert.equal(impressionObj[0].banner.h, slotSizes_1[1], "the height made in the request matches with request: " + slotSizes_1[1] ); - assert.equal(impressionObj[0].ext.sid, slotID_1, "slotID in the request matches with configuration: " + slotID_1 ); - assert.equal(impressionObj[0].ext.siteID, IndexUtils.DefaultSiteID, "siteID in the request matches with request: " + IndexUtils.DefaultSiteID ); - - assert.equal(impressionObj[1].banner.w, slotSizes_2[0], "the width made in the request matches with request: " + slotSizes_2[0] ); - assert.equal(impressionObj[1].banner.h, slotSizes_2[1], "the height made in the request matches with request: " + slotSizes_2[1] ); - assert.equal(impressionObj[1].ext.sid, slotID_2, "slotID in the request matches with configuration: " + slotID_2 ); - assert.equal(impressionObj[1].ext.siteID, IndexUtils.DefaultSiteID, "siteID in the request matches with request: " + IndexUtils.DefaultSiteID ); - }); - - it('test_prebid_indexAdapter_request_sizeID_4: multiple prebid size slot, 1 index slot but size not in prebid defined size git -> no AS requset', function () { - var slotID = 52; - var slotSizes = IndexUtils.unsupportedSizes[0]; - - var configuredBids = [ - IndexUtils.createBidSlot( IndexUtils.DefaultPlacementCodePrefix, slotID, [ IndexUtils.supportedSizes[0] ], { slotSize : slotSizes } ) - ]; - - adapter.callBids({ bids: configuredBids }); - - assert.isUndefined( adLoader.loadScript.firstCall.args[0], "no request made to AS"); - }); - - it('test_prebid_indexAdapter_request_sizeID_5: multiple prebid size slot, 1 index slot but size not defined in slot -> no AS requset', function () { - var slotID = 52; - var slotSizes = IndexUtils.supportedSizes[1]; - - var configuredBids = [ - IndexUtils.createBidSlot( IndexUtils.DefaultPlacementCodePrefix, slotID, [ IndexUtils.supportedSizes[0] ], { slotSize : slotSizes } ) - ]; - - adapter.callBids({ bids: configuredBids }); - - assert.isUndefined( adLoader.loadScript.firstCall.args[0], "no request made to AS"); - }); -}); diff --git a/test/spec/adapters/indexExchange_response_spec.js b/test/spec/adapters/indexExchange_response_spec.js deleted file mode 100644 index e258620727c..00000000000 --- a/test/spec/adapters/indexExchange_response_spec.js +++ /dev/null @@ -1,1181 +0,0 @@ -import Adapter from '../../../src/adapters/indexExchange'; -import bidManager from '../../../src/bidmanager'; -import adLoader from '../../../src/adloader'; - -var assert = require('chai').assert; -var IndexUtils = require('../../helpers/index_adapter_utils.js'); -var HeaderTagRequest = '/cygnus'; -var SlotThreshold = 20; -var ADAPTER_CODE = 'indexExchange'; -var DefaultValue = { - dealID : 'IXDeal' -}; -window.pbjs = window.pbjs || {}; -var ResponseStatus = { - noBid: "Bid returned empty or error response" -}; - -describe('indexExchange adapter - Response', function () { - let adapter; - let sandbox; - - beforeEach( function() { - window._IndexRequestData = {}; - _IndexRequestData.impIDToSlotID = {}; - _IndexRequestData.reqOptions = {}; - _IndexRequestData.targetIDToResp = {}; - window.cygnus_index_args = {}; - - adapter = new Adapter(); - sandbox = sinon.sandbox.create(); - sandbox.stub(bidManager, 'addBidResponse'); - sandbox.stub(adLoader, 'loadScript'); - }); - - afterEach( function() { - sandbox.restore(); - }); - - it('test_prebid_indexAdapter_response_1_1: response for single slot with single size -> bid fetched into prebid', function () { - var configuredBids = IndexUtils.createBidSlots(1, 1); - adapter.callBids({ bids: configuredBids }); - - var requestJSON = IndexUtils.parseIndexRequest(adLoader.loadScript.firstCall.args[0]); - var asResponse = IndexUtils.getBidResponse( configuredBids, requestJSON ); - cygnus_index_parse_res( asResponse ); - - var expectedAdapterResponse = IndexUtils.getExpectedAdaptorResponse( configuredBids, asResponse ); - - var adapterResponse = {}; - - for ( var i = 0; i < bidManager.addBidResponse.callCount; i++ ) { - var adUnitCode = bidManager.addBidResponse.getCall(i).args[0]; - var bid = bidManager.addBidResponse.getCall(i).args[1]; - - if ( typeof adapterResponse[adUnitCode] === 'undefined'){ - adapterResponse[adUnitCode] = []; - }; - adapterResponse[adUnitCode].push(bid); - } - - var prebidResponsePair = IndexUtils.matchOnPlacementCode(expectedAdapterResponse, adapterResponse); - for ( var i = 0; i < prebidResponsePair.matched.length; i++) { - var pair = prebidResponsePair.matched[i]; - assert.equal( pair.prebid.length, 1, "Only one bid is ferched into prebid"); - assert.equal(pair.prebid[0].siteID, pair.expected[0].siteID, "adapter response for " + pair.placementCode + " siteID is set to "+pair.expected[0].siteID); - assert.equal(pair.prebid[0].bidderCode, pair.expected[0].bidderCode, "adapter response for " + pair.placementCode + " bidderCode is set to "+pair.expected[0].bidderCode); - assert.equal(pair.prebid[0].width, pair.expected[0].width, "adapter response for " + pair.placementCode + " width is set to "+pair.expected[0].width); - assert.equal(pair.prebid[0].height, pair.expected[0].height, "adapter response for " + pair.placementCode + " height is set to "+pair.expected[0].height); - assert.equal(pair.prebid[0].ad, pair.expected[0].ad, "adapter response for " + pair.placementCode + " ad is set to "+pair.expected[0].ad); - assert.equal(pair.prebid[0].cpm, pair.expected[0].cpm, "adapter response for " + pair.placementCode + " cpm is set to "+pair.expected[0].cpm); - } - - assert.equal( prebidResponsePair.unmatched.expected.length, 0, "All AS bid response translated to Adapter response for prebid"); - assert.equal( prebidResponsePair.unmatched.prebid.length, 0, "All Adapter response for prebid is from AS bid"); - }); - - it('test_prebid_indexAdapter_response_1_2: pass on bid for single slot with single size -> bid fetched into prebid', function () { - var configuredBids = [ - IndexUtils.createBidSlot( IndexUtils.DefaultPlacementCodePrefix, 'slot1', [ IndexUtils.supportedSizes[0] ] ), - ]; - adapter.callBids({ bids: configuredBids }); - - var requestJSON = IndexUtils.parseIndexRequest(adLoader.loadScript.firstCall.args[0]); - var asResponse = IndexUtils.getBidResponse( configuredBids, requestJSON, undefined, undefined, [ [ true ] ] ); - cygnus_index_parse_res( asResponse ); - - var expectedAdapterResponse = IndexUtils.getExpectedAdaptorResponse( configuredBids, asResponse ); - - var adapterResponse = {}; - - for ( var i = 0; i < bidManager.addBidResponse.callCount; i++ ) { - var adUnitCode = bidManager.addBidResponse.getCall(i).args[0]; - var bid = bidManager.addBidResponse.getCall(i).args[1]; - - if ( typeof adapterResponse[adUnitCode] === 'undefined'){ - adapterResponse[adUnitCode] = []; - }; - adapterResponse[adUnitCode].push(bid); - } - - var prebidResponsePair = IndexUtils.matchOnPlacementCode(expectedAdapterResponse, adapterResponse); - - assert.equal( prebidResponsePair.matched.length, 0, 'No bids are added to prebid' ); - assert.equal( prebidResponsePair.unmatched.expected.length, 0, "All AS bid response translated to Adapter response for prebid"); - assert.equal( prebidResponsePair.unmatched.prebid.length, 1, "no Adapter response for prebid is from AS bid"); - }); - - - it('test_prebid_indexAdapter_response_2_1: response for single slot with multiple sizes -> all bids fetched into prebid', function () { - var configuredBids = IndexUtils.createBidSlots(1, 3); - adapter.callBids({ bids: configuredBids }); - - var requestJSON = IndexUtils.parseIndexRequest(adLoader.loadScript.firstCall.args[0]); - - var asResponse = IndexUtils.getBidResponse( configuredBids, requestJSON ); - cygnus_index_parse_res( asResponse ); - - var expectedAdapterResponse = IndexUtils.getExpectedAdaptorResponse( configuredBids, asResponse, [ [1000, 3000, 2000] ]); - - var adapterResponse = {}; - - for ( var i = 0; i < bidManager.addBidResponse.callCount; i++ ) { - var adUnitCode = bidManager.addBidResponse.getCall(i).args[0]; - var bid = bidManager.addBidResponse.getCall(i).args[1]; - - if ( typeof adapterResponse[adUnitCode] === 'undefined'){ - adapterResponse[adUnitCode] = []; - }; - adapterResponse[adUnitCode].push(bid); - } - - var prebidResponsePair = IndexUtils.matchOnPlacementCode(expectedAdapterResponse, adapterResponse); - - for ( var i = 0; i < prebidResponsePair.matched.length; i++) { - var pair = prebidResponsePair.matched[i]; - - assert.equal(pair.prebid.length, 3, "all bids are fetched into prebid"); - for ( var j = 0; j < pair.prebid.length; j++) { - assert.equal(pair.prebid[j].siteID, pair.expected[j].siteID, "adapter response for " + pair.placementCode + " siteID is set to "+pair.expected[j].siteID); - assert.equal(pair.prebid[j].bidderCode, pair.expected[j].bidderCode, "adapter response for " + pair.placementCode + " bidderCode is set to "+pair.expected[j].bidderCode); - assert.equal(pair.prebid[j].width, pair.expected[j].width, "adapter response for " + pair.placementCode + " width is set to "+pair.expected[j].width); - assert.equal(pair.prebid[j].height, pair.expected[j].height, "adapter response for " + pair.placementCode + " height is set to "+pair.expected[j].height); - assert.equal(pair.prebid[j].ad, pair.expected[j].ad, "adapter response for " + pair.placementCode + " ad is set to "+pair.expected[j].ad); - assert.equal(pair.prebid[j].cpm, pair.expected[j].cpm, "adapter response for " + pair.placementCode + " cpm is set to "+pair.expected[j].cpm); - } - } - - assert.equal( prebidResponsePair.unmatched.expected.length, 0, "All AS bid response translated to Adapter response for prebid"); - assert.equal( prebidResponsePair.unmatched.prebid.length, 0, "All Adapter response for prebid is from AS bid"); - }); - - it('test_prebid_indexAdapter_response_2_2: pass on bid on some sizes for single slot with multiple sizes -> highest bid fetched into prebid', function () { - var configuredBids = [ - IndexUtils.createBidSlot( IndexUtils.DefaultPlacementCodePrefix, 'slot1', [ IndexUtils.supportedSizes[0], IndexUtils.supportedSizes[1] ] ), - ]; - adapter.callBids({ bids: configuredBids }); - - var requestJSON = IndexUtils.parseIndexRequest(adLoader.loadScript.firstCall.args[0]); - - // pass on bid on second size - var asResponse = IndexUtils.getBidResponse( configuredBids, requestJSON, undefined, undefined, [ [ false, true ] ] ); - cygnus_index_parse_res( asResponse ); - - var expectedAdapterResponse = IndexUtils.getExpectedAdaptorResponse( configuredBids, asResponse ); - - var adapterResponse = {}; - - for ( var i = 0; i < bidManager.addBidResponse.callCount; i++ ) { - var adUnitCode = bidManager.addBidResponse.getCall(i).args[0]; - var bid = bidManager.addBidResponse.getCall(i).args[1]; - - if ( typeof adapterResponse[adUnitCode] === 'undefined'){ - adapterResponse[adUnitCode] = []; - }; - adapterResponse[adUnitCode].push(bid); - } - - var prebidResponsePair = IndexUtils.matchOnPlacementCode(expectedAdapterResponse, adapterResponse); - - assert.equal( prebidResponsePair.matched.length, 1, 'one slot is added to prebid' ); - var pair = prebidResponsePair.matched[0]; - assert.equal(pair.prebid[0].siteID, pair.expected[0].siteID, "adapter response for " + pair.placementCode + " siteID is set to "+pair.expected[0].siteID); - assert.equal(pair.prebid[0].bidderCode, pair.expected[0].bidderCode, "adapter response for " + pair.placementCode + " bidderCode is set to "+pair.expected[0].bidderCode); - assert.equal(pair.prebid[0].width, pair.expected[0].width, "adapter response for " + pair.placementCode + " width is set to "+pair.expected[0].width); - assert.equal(pair.prebid[0].height, pair.expected[0].height, "adapter response for " + pair.placementCode + " height is set to "+pair.expected[0].height); - assert.equal(pair.prebid[0].ad, pair.expected[0].ad, "adapter response for " + pair.placementCode + " ad is set to "+pair.expected[0].ad); - assert.equal(pair.prebid[0].cpm, pair.expected[0].cpm, "adapter response for " + pair.placementCode + " cpm is set to "+pair.expected[0].cpm); - - assert.equal( prebidResponsePair.unmatched.expected.length, 0, "All AS bid response translated to Adapter response for prebid"); - assert.equal( prebidResponsePair.unmatched.prebid.length, 0, "All Adapter response for prebid is from AS bid"); - }); - - it('test_prebid_indexAdapter_response_2_3: pass on bid on all sizes for a single slot -> no bids fetched into prebid', function () { - var configuredBids = [ - IndexUtils.createBidSlot( IndexUtils.DefaultPlacementCodePrefix, 'slot1', [ IndexUtils.supportedSizes[0], IndexUtils.supportedSizes[1] ] ), - ]; - adapter.callBids({ bids: configuredBids }); - - var requestJSON = IndexUtils.parseIndexRequest(adLoader.loadScript.firstCall.args[0]); - - // pass on bid on all bids - var asResponse = IndexUtils.getBidResponse( configuredBids, requestJSON, undefined, undefined, [ [ true, true ] ] ); - cygnus_index_parse_res( asResponse ); - - var expectedAdapterResponse = IndexUtils.getExpectedAdaptorResponse( configuredBids, asResponse ); - - var adapterResponse = {}; - - for ( var i = 0; i < bidManager.addBidResponse.callCount; i++ ) { - var adUnitCode = bidManager.addBidResponse.getCall(i).args[0]; - var bid = bidManager.addBidResponse.getCall(i).args[1]; - - if ( typeof adapterResponse[adUnitCode] === 'undefined'){ - adapterResponse[adUnitCode] = []; - }; - adapterResponse[adUnitCode].push(bid); - } - - var prebidResponsePair = IndexUtils.matchOnPlacementCode(expectedAdapterResponse, adapterResponse); - - assert.equal( prebidResponsePair.matched.length, 0, 'no bids fetched into prebid' ); - assert.equal( prebidResponsePair.unmatched.expected.length, 0, "All AS bid response translated to Adapter response for prebid"); - assert.equal( prebidResponsePair.unmatched.prebid[0][0].statusMessage, ResponseStatus.noBid, "Bid response status is set to " + ResponseStatus.noBid ); - }); - - it('test_prebid_indexAdapter_response_3_1: response for multiple slots request with single size for each slots -> all response for all adunit fetched into prebid', function () { - var configuredBids = IndexUtils.createBidSlots(20); - adapter.callBids({ bids: configuredBids }); - - var requestJSON = IndexUtils.parseIndexRequest(adLoader.loadScript.firstCall.args[0]); - - var asResponse = IndexUtils.getBidResponse( configuredBids, requestJSON ); - cygnus_index_parse_res( asResponse ); - - var expectedAdapterResponse = IndexUtils.getExpectedAdaptorResponse( configuredBids, asResponse, [ [1000, 3000, 2000] ]); - - var adapterResponse = {}; - - for ( var i = 0; i < bidManager.addBidResponse.callCount; i++ ) { - var adUnitCode = bidManager.addBidResponse.getCall(i).args[0]; - var bid = bidManager.addBidResponse.getCall(i).args[1]; - - if ( typeof adapterResponse[adUnitCode] === 'undefined'){ - adapterResponse[adUnitCode] = []; - }; - adapterResponse[adUnitCode].push(bid); - } - - var prebidResponsePair = IndexUtils.matchOnPlacementCode(expectedAdapterResponse, adapterResponse); - - for ( var i = 0; i < prebidResponsePair.matched.length; i++) { - var pair = prebidResponsePair.matched[i]; - - assert.equal(pair.prebid.length, 1, "all bids are fetched into prebid"); - assert.equal(pair.prebid[0].siteID, pair.expected[0].siteID, "adapter response for " + pair.placementCode + " siteID is set to "+pair.expected[0].siteID); - assert.equal(pair.prebid[0].bidderCode, pair.expected[0].bidderCode, "adapter response for " + pair.placementCode + " bidderCode is set to "+pair.expected[0].bidderCode); - assert.equal(pair.prebid[0].width, pair.expected[0].width, "adapter response for " + pair.placementCode + " width is set to "+pair.expected[0].width); - assert.equal(pair.prebid[0].height, pair.expected[0].height, "adapter response for " + pair.placementCode + " height is set to "+pair.expected[0].height); - assert.equal(pair.prebid[0].ad, pair.expected[0].ad, "adapter response for " + pair.placementCode + " ad is set to "+pair.expected[0].ad); - assert.equal(pair.prebid[0].cpm, pair.expected[0].cpm, "adapter response for " + pair.placementCode + " cpm is set to "+pair.expected[0].cpm); - } - - assert.equal( prebidResponsePair.unmatched.expected.length, 0, "All AS bid response translated to Adapter response for prebid"); - assert.equal( prebidResponsePair.unmatched.prebid.length, 0, "All Adapter response for prebid is from AS bid"); - }); - - it('test_prebid_indexAdapter_response_3_2: some slots response returned -> returned bids fetched into prebid ', function () { - var configuredBids = IndexUtils.createBidSlots(2); - adapter.callBids({ bids: configuredBids }); - - var requestJSON = IndexUtils.parseIndexRequest(adLoader.loadScript.firstCall.args[0]); - - var passOnBid = [ - [ false ], // bids back on first slot - [ true ], // pass on bid on second slot - ]; - var asResponse = IndexUtils.getBidResponse( configuredBids, requestJSON, undefined, undefined, passOnBid ); - cygnus_index_parse_res( asResponse ); - - var expectedAdapterResponse = IndexUtils.getExpectedAdaptorResponse( configuredBids, asResponse, [ [1000, 3000, 2000] ]); - - var adapterResponse = {}; - - for ( var i = 0; i < bidManager.addBidResponse.callCount; i++ ) { - var adUnitCode = bidManager.addBidResponse.getCall(i).args[0]; - var bid = bidManager.addBidResponse.getCall(i).args[1]; - - if ( typeof adapterResponse[adUnitCode] === 'undefined'){ - adapterResponse[adUnitCode] = []; - }; - adapterResponse[adUnitCode].push(bid); - } - - var prebidResponsePair = IndexUtils.matchOnPlacementCode(expectedAdapterResponse, adapterResponse); - - assert.equal( prebidResponsePair.matched.length, 1, "1 bid from ad server is fetched into prebid"); - for ( var i = 0; i < prebidResponsePair.matched.length; i++) { - var pair = prebidResponsePair.matched[i]; - - assert.equal(pair.prebid.length, 1, "all bids are fetched into prebid"); - assert.equal(pair.prebid[0].siteID, pair.expected[0].siteID, "adapter response for " + pair.placementCode + " siteID is set to "+pair.expected[0].siteID); - assert.equal(pair.prebid[0].bidderCode, pair.expected[0].bidderCode, "adapter response for " + pair.placementCode + " bidderCode is set to "+pair.expected[0].bidderCode); - assert.equal(pair.prebid[0].width, pair.expected[0].width, "adapter response for " + pair.placementCode + " width is set to "+pair.expected[0].width); - assert.equal(pair.prebid[0].height, pair.expected[0].height, "adapter response for " + pair.placementCode + " height is set to "+pair.expected[0].height); - assert.equal(pair.prebid[0].ad, pair.expected[0].ad, "adapter response for " + pair.placementCode + " ad is set to "+pair.expected[0].ad); - assert.equal(pair.prebid[0].cpm, pair.expected[0].cpm, "adapter response for " + pair.placementCode + " cpm is set to "+pair.expected[0].cpm); - } - - assert.equal( prebidResponsePair.unmatched.expected.length, 0, "All AS bid response translated to Adapter response for prebid"); - assert.equal( prebidResponsePair.unmatched.prebid.length, 1, "One slot passed on bid from Ad Server"); - }); - - it('test_prebid_indexAdapter_response_3_3: response for multiple slots with no response returned -> no bid fetched into prebid', function () { - var configuredBids = IndexUtils.createBidSlots(2); - adapter.callBids({ bids: configuredBids }); - - var requestJSON = IndexUtils.parseIndexRequest(adLoader.loadScript.firstCall.args[0]); - - var passOnBid = [ - [ true ], // pass on bid on the first slot - [ true ], // pass on bid on the second slot - ]; - var asResponse = IndexUtils.getBidResponse( configuredBids, requestJSON, undefined, undefined, passOnBid ); - cygnus_index_parse_res( asResponse ); - - var expectedAdapterResponse = IndexUtils.getExpectedAdaptorResponse( configuredBids, asResponse, [ [1000, 3000, 2000] ]); - - var adapterResponse = {}; - - for ( var i = 0; i < bidManager.addBidResponse.callCount; i++ ) { - var adUnitCode = bidManager.addBidResponse.getCall(i).args[0]; - var bid = bidManager.addBidResponse.getCall(i).args[1]; - - if ( typeof adapterResponse[adUnitCode] === 'undefined'){ - adapterResponse[adUnitCode] = []; - }; - adapterResponse[adUnitCode].push(bid); - } - - var prebidResponsePair = IndexUtils.matchOnPlacementCode(expectedAdapterResponse, adapterResponse); - - assert.equal( prebidResponsePair.matched.length, 0, "no bids from ad server is fetched into prebid"); - - assert.equal( prebidResponsePair.unmatched.expected.length, 0, "All AS bid response translated to Adapter response for prebid"); - assert.equal( prebidResponsePair.unmatched.prebid.length, 2, "two slots passed on bid from Ad Server"); - }); - - it("test_prebid_indexAdapter_refreshSlot_1: slot refreshes multiple times with different bids on refresh with same price -> response to prebid use correct AS response's creative", function () { - var configuredBids = IndexUtils.createBidSlots(1, 1); - - var refreshSetup = [ {price:1000, request:"request-1"}, {price:1000, request:"request-2"} ]; - for( var i=0; i response to prebid use correct AS response's creative", function () { - var configuredBids = IndexUtils.createBidSlots(1, 1); - - var refreshSetup = [ {price:8000, request:"request-1"}, {price:1000, request:"request-2"} ]; - for( var i=0; i response to prebid use correct AS response's creative", function () { - var configuredBids = IndexUtils.createBidSlots(1, 1); - - var refreshSetup = [ {price:1000, request:"request-1"}, {price:8000, request:"request-2"} ]; - for( var i=0; i no bids fetched into prebid", function () { - var configuredBids = IndexUtils.createBidSlots(1, 1); - - var refreshSetup = [ { price:1000, request:"request-1", passOnBid: false}, { price:1000, request:"request-2", passOnBid: true} ]; - for( var i=0; i no ad server request, no bids fetched into prebid", function () { - var configuredBids = [ - IndexUtils.createBidSlot( IndexUtils.DefaultPlacementCodePrefix, "slot_1", [ IndexUtils.unsupportedSizes[0] ] ) - ]; - - var refreshSetup = [ { request:"request-1" }, { request:"request-2" } ]; - for( var i=0; i bid fetched into prebid', function () { - var configuredBids = IndexUtils.createBidSlots(1, 1); - adapter.callBids({ bids: configuredBids }); - - var requestJSON = IndexUtils.parseIndexRequest(adLoader.loadScript.firstCall.args[0]); - var optionalResponseParam = [ - [ - { ext: { dealid: 'ixDeal' } } // first slot first size - ] - ]; - var asResponse = IndexUtils.getBidResponse( configuredBids, requestJSON, undefined, undefined, undefined, optionalResponseParam ); - cygnus_index_parse_res( asResponse ); - - var expectedAdapterResponse = IndexUtils.getExpectedAdaptorResponse( configuredBids, asResponse ); - - var adapterResponse = {}; - - for ( var i = 0; i < bidManager.addBidResponse.callCount; i++ ) { - var adUnitCode = bidManager.addBidResponse.getCall(i).args[0]; - var bid = bidManager.addBidResponse.getCall(i).args[1]; - - if ( typeof adapterResponse[adUnitCode] === 'undefined'){ - adapterResponse[adUnitCode] = []; - }; - adapterResponse[adUnitCode].push(bid); - } - - var prebidResponsePair = IndexUtils.matchOnPlacementCode(expectedAdapterResponse, adapterResponse); - for ( var i = 0; i < prebidResponsePair.matched.length; i++) { - var pair = prebidResponsePair.matched[i]; - - assert.equal(pair.prebid[i].siteID, pair.expected[i].siteID, "adapter response for " + pair.placementCode + " siteID is set to "+pair.expected[i].siteID); - assert.equal(pair.prebid[i].bidderCode, pair.expected[i].bidderCode, "adapter response for " + pair.placementCode + " bidderCode is set to "+pair.expected[i].bidderCode); - assert.equal(pair.prebid[i].width, pair.expected[i].width, "adapter response for " + pair.placementCode + " width is set to "+pair.expected[i].width); - assert.equal(pair.prebid[i].height, pair.expected[i].height, "adapter response for " + pair.placementCode + " height is set to "+pair.expected[i].height); - assert.equal(pair.prebid[i].ad, pair.expected[i].ad, "adapter response for " + pair.placementCode + " ad is set to "+pair.expected[i].ad); - assert.equal(pair.prebid[i].cpm, pair.expected[i].cpm, "adapter response for " + pair.placementCode + " cpm is set to "+pair.expected[i].cpm); - assert.equal(pair.prebid[i].dealId, pair.expected[i].dealId, "adapter response for " + pair.placementCode + " deaiid is set to "+pair.expected[i].dealId); - } - - assert.equal( prebidResponsePair.unmatched.expected.length, 0, "All AS bid response translated to Adapter response for prebid"); - assert.equal( prebidResponsePair.unmatched.prebid.length, 0, "All Adapter response for prebid is from AS bid"); - }); - - it('test_prebid_indexAdapter_response_deal_1_2: response for single slot with single size contains numeric deal -> bid fetched into prebid', function () { - var configuredBids = IndexUtils.createBidSlots(1, 1); - adapter.callBids({ bids: configuredBids }); - - var requestJSON = IndexUtils.parseIndexRequest(adLoader.loadScript.firstCall.args[0]); - var optionalResponseParam = [ - [ - { ext: { dealid: '239' } } // first slot first size - ] - ]; - var asResponse = IndexUtils.getBidResponse( configuredBids, requestJSON, undefined, undefined, undefined, optionalResponseParam ); - cygnus_index_parse_res( asResponse ); - var expectedAdapterResponse = IndexUtils.getExpectedAdaptorResponse( configuredBids, asResponse ); - - var adapterResponse = {}; - - for ( var i = 0; i < bidManager.addBidResponse.callCount; i++ ) { - var adUnitCode = bidManager.addBidResponse.getCall(i).args[0]; - var bid = bidManager.addBidResponse.getCall(i).args[1]; - - if ( typeof adapterResponse[adUnitCode] === 'undefined'){ - adapterResponse[adUnitCode] = []; - }; - adapterResponse[adUnitCode].push(bid); - } - - var prebidResponsePair = IndexUtils.matchOnPlacementCode(expectedAdapterResponse, adapterResponse); - - for ( var i = 0; i < prebidResponsePair.matched.length; i++) { - var pair = prebidResponsePair.matched[i]; - - assert.equal(pair.prebid[i].siteID, pair.expected[i].siteID, "adapter response for " + pair.placementCode + " siteID is set to "+pair.expected[i].siteID); - assert.equal(pair.prebid[i].bidderCode, pair.expected[i].bidderCode, "adapter response for " + pair.placementCode + " bidderCode is set to "+pair.expected[i].bidderCode); - assert.equal(pair.prebid[i].width, pair.expected[i].width, "adapter response for " + pair.placementCode + " width is set to "+pair.expected[i].width); - assert.equal(pair.prebid[i].height, pair.expected[i].height, "adapter response for " + pair.placementCode + " height is set to "+pair.expected[i].height); - assert.equal(pair.prebid[i].ad, pair.expected[i].ad, "adapter response for " + pair.placementCode + " ad is set to "+pair.expected[i].ad); - assert.equal(pair.prebid[i].cpm, pair.expected[i].cpm, "adapter response for " + pair.placementCode + " cpm is set to "+pair.expected[i].cpm); - assert.equal(pair.prebid[i].dealId, pair.expected[i].dealId, "adapter response for " + pair.placementCode + " deaiid is set to "+pair.expected[i].dealId); - } - - assert.equal( prebidResponsePair.unmatched.expected.length, 0, "All AS bid response translated to Adapter response for prebid"); - assert.equal( prebidResponsePair.unmatched.prebid.length, 0, "All Adapter response for prebid is from AS bid"); - }); - - - it('test_prebid_indexAdapter_response_deal_1_3: response for single slot with single size contains alpha-numeric deal starting with numeric -> bid fetched into prebid', function () { - var configuredBids = IndexUtils.createBidSlots(1, 1); - adapter.callBids({ bids: configuredBids }); - - var requestJSON = IndexUtils.parseIndexRequest(adLoader.loadScript.firstCall.args[0]); - var optionalResponseParam = [ - [ - { ext: { dealid: '1234Deal' } } // first slot first size - ] - ]; - var asResponse = IndexUtils.getBidResponse( configuredBids, requestJSON, undefined, undefined, undefined, optionalResponseParam ); - cygnus_index_parse_res( asResponse ); - var expectedAdapterResponse = IndexUtils.getExpectedAdaptorResponse( configuredBids, asResponse ); - - var adapterResponse = {}; - - for ( var i = 0; i < bidManager.addBidResponse.callCount; i++ ) { - var adUnitCode = bidManager.addBidResponse.getCall(i).args[0]; - var bid = bidManager.addBidResponse.getCall(i).args[1]; - - if ( typeof adapterResponse[adUnitCode] === 'undefined'){ - adapterResponse[adUnitCode] = []; - }; - adapterResponse[adUnitCode].push(bid); - } - - var prebidResponsePair = IndexUtils.matchOnPlacementCode(expectedAdapterResponse, adapterResponse); - - for ( var i = 0; i < prebidResponsePair.matched.length; i++) { - var pair = prebidResponsePair.matched[i]; - - assert.equal(pair.prebid[i].siteID, pair.expected[i].siteID, "adapter response for " + pair.placementCode + " siteID is set to "+pair.expected[i].siteID); - assert.equal(pair.prebid[i].bidderCode, pair.expected[i].bidderCode, "adapter response for " + pair.placementCode + " bidderCode is set to "+pair.expected[i].bidderCode); - assert.equal(pair.prebid[i].width, pair.expected[i].width, "adapter response for " + pair.placementCode + " width is set to "+pair.expected[i].width); - assert.equal(pair.prebid[i].height, pair.expected[i].height, "adapter response for " + pair.placementCode + " height is set to "+pair.expected[i].height); - assert.equal(pair.prebid[i].ad, pair.expected[i].ad, "adapter response for " + pair.placementCode + " ad is set to "+pair.expected[i].ad); - assert.equal(pair.prebid[i].cpm, pair.expected[i].cpm, "adapter response for " + pair.placementCode + " cpm is set to "+pair.expected[i].cpm); - assert.equal(pair.prebid[i].dealId, pair.expected[i].dealId, "adapter response for " + pair.placementCode + " deaiid is set to "+pair.expected[i].dealId); - } - - assert.equal( prebidResponsePair.unmatched.expected.length, 0, "All AS bid response translated to Adapter response for prebid"); - assert.equal( prebidResponsePair.unmatched.prebid.length, 0, "All Adapter response for prebid is from AS bid"); - }); - - it('test_prebid_indexAdapter_response_deal_1_4: response for single slot with single size contains alpha-numeric deal starting with non-numeric -> bid fetched into prebid ', function () { - var configuredBids = IndexUtils.createBidSlots(1, 1); - adapter.callBids({ bids: configuredBids }); - - var requestJSON = IndexUtils.parseIndexRequest(adLoader.loadScript.firstCall.args[0]); - var optionalResponseParam = [ - [ - { ext: { dealid: 'deal1234' } } // first slot first size - ] - ]; - var asResponse = IndexUtils.getBidResponse( configuredBids, requestJSON, undefined, undefined, undefined, optionalResponseParam ); // Alpha numeric starting with non-numeric - cygnus_index_parse_res( asResponse ); - var expectedAdapterResponse = IndexUtils.getExpectedAdaptorResponse( configuredBids, asResponse ); - - var adapterResponse = {}; - - for ( var i = 0; i < bidManager.addBidResponse.callCount; i++ ) { - var adUnitCode = bidManager.addBidResponse.getCall(i).args[0]; - var bid = bidManager.addBidResponse.getCall(i).args[1]; - - if ( typeof adapterResponse[adUnitCode] === 'undefined'){ - adapterResponse[adUnitCode] = []; - }; - adapterResponse[adUnitCode].push(bid); - } - - var prebidResponsePair = IndexUtils.matchOnPlacementCode(expectedAdapterResponse, adapterResponse); - - for ( var i = 0; i < prebidResponsePair.matched.length; i++) { - var pair = prebidResponsePair.matched[i]; - - assert.equal(pair.prebid[i].siteID, pair.expected[i].siteID, "adapter response for " + pair.placementCode + " siteID is set to "+pair.expected[i].siteID); - assert.equal(pair.prebid[i].bidderCode, pair.expected[i].bidderCode, "adapter response for " + pair.placementCode + " bidderCode is set to "+pair.expected[i].bidderCode); - assert.equal(pair.prebid[i].width, pair.expected[i].width, "adapter response for " + pair.placementCode + " width is set to "+pair.expected[i].width); - assert.equal(pair.prebid[i].height, pair.expected[i].height, "adapter response for " + pair.placementCode + " height is set to "+pair.expected[i].height); - assert.equal(pair.prebid[i].ad, pair.expected[i].ad, "adapter response for " + pair.placementCode + " ad is set to "+pair.expected[i].ad); - assert.equal(pair.prebid[i].cpm, pair.expected[i].cpm, "adapter response for " + pair.placementCode + " cpm is set to "+pair.expected[i].cpm); - assert.equal(pair.prebid[i].dealId, pair.expected[i].dealId, "adapter response for " + pair.placementCode + " deaiid is set to "+pair.expected[i].dealId); - } - - assert.equal( prebidResponsePair.unmatched.expected.length, 0, "All AS bid response translated to Adapter response for prebid"); - assert.equal( prebidResponsePair.unmatched.prebid.length, 0, "All Adapter response for prebid is from AS bid"); - }); - - - - it('test_prebid_indexAdapter_response_deal_2_1: response for single slot with multi size, all deal bids returned -> all bid fetched into prebid as deal bid', function () { - var sizeCount = 2; - var configuredBids = IndexUtils.createBidSlots(1, sizeCount); - adapter.callBids({ bids: configuredBids }); - - var requestJSON = IndexUtils.parseIndexRequest(adLoader.loadScript.firstCall.args[0]); - var optionalResponseParam = [ - [ - { ext: { deal: 'deal1', dealid: 'ixDealID1', dealname: 'deal name 1' } }, // first slot first size - { ext: { deal: 'deal2', dealid: 'ixDealID2', dealname: 'deal name 2' } }, // first slot second size - ] - ]; - var asResponse = IndexUtils.getBidResponse( configuredBids, requestJSON, undefined, undefined, undefined, optionalResponseParam ); - cygnus_index_parse_res( asResponse ); - var expectedAdapterResponse = IndexUtils.getExpectedAdaptorResponse( configuredBids, asResponse ); - - var adapterResponse = {}; - - for ( var i = 0; i < bidManager.addBidResponse.callCount; i++ ) { - var adUnitCode = bidManager.addBidResponse.getCall(i).args[0]; - var bid = bidManager.addBidResponse.getCall(i).args[1]; - - if ( typeof adapterResponse[adUnitCode] === 'undefined'){ - adapterResponse[adUnitCode] = []; - }; - adapterResponse[adUnitCode].push(bid); - } - - var prebidResponsePair = IndexUtils.matchOnPlacementCode(expectedAdapterResponse, adapterResponse); - for ( var i = 0; i < prebidResponsePair.matched.length; i++) { - var pair = prebidResponsePair.matched[i]; - - for ( var j = 0; j < pair.expected.length; j++ ) { - assert.equal(pair.prebid[j].siteID, pair.expected[j].siteID, "adapter response for " + pair.placementCode + " siteID is set to "+pair.expected[i].siteID); - assert.equal(pair.prebid[j].bidderCode, pair.expected[j].bidderCode, "adapter response for " + pair.placementCode + " bidderCode is set to "+pair.expected[i].bidderCode); - assert.equal(pair.prebid[j].width, pair.expected[j].width, "adapter response for " + pair.placementCode + " width is set to "+pair.expected[i].width); - assert.equal(pair.prebid[j].height, pair.expected[j].height, "adapter response for " + pair.placementCode + " height is set to "+pair.expected[i].height); - assert.equal(pair.prebid[j].ad, pair.expected[j].ad, "adapter response for " + pair.placementCode + " ad is set to "+pair.expected[i].ad); - assert.equal(pair.prebid[j].cpm, pair.expected[j].cpm, "adapter response for " + pair.placementCode + " cpm is set to "+pair.expected[i].cpm); - assert.equal(pair.prebid[j].dealId, pair.expected[j].dealId, "adapter response for " + pair.placementCode + " deaiid is set to "+pair.expected[i].dealId); - } - } - assert.equal( prebidResponsePair.unmatched.expected.length, 0, "All AS bid response translated to Adapter response for prebid"); - assert.equal( prebidResponsePair.unmatched.prebid.length, 0, "All Adapter response for prebid is from AS bid"); - }); - - - it('test_prebid_indexAdapter_response_deal_2_2: response for single slot with multi size, some deal resposne returned and the rest non deal response -> all bid fetched, only deal response has dealID', function () { - var sizeCount = 2; - var configuredBids = IndexUtils.createBidSlots(1, sizeCount); - adapter.callBids({ bids: configuredBids }); - - var requestJSON = IndexUtils.parseIndexRequest(adLoader.loadScript.firstCall.args[0]); - var optionalResponseParam = [ - [ - { ext: { deal: 'deal1', dealid: 'ixDealID1', dealname: 'deal name 1' } } // first slot first size - // No deal on first slot second size - ] - ]; - var asResponse = IndexUtils.getBidResponse( configuredBids, requestJSON, undefined, undefined, undefined, optionalResponseParam ); - cygnus_index_parse_res( asResponse ); - var expectedAdapterResponse = IndexUtils.getExpectedAdaptorResponse( configuredBids, asResponse ); - - var adapterResponse = {}; - - for ( var i = 0; i < bidManager.addBidResponse.callCount; i++ ) { - var adUnitCode = bidManager.addBidResponse.getCall(i).args[0]; - var bid = bidManager.addBidResponse.getCall(i).args[1]; - - if ( typeof adapterResponse[adUnitCode] === 'undefined'){ - adapterResponse[adUnitCode] = []; - }; - adapterResponse[adUnitCode].push(bid); - } - - var prebidResponsePair = IndexUtils.matchOnPlacementCode(expectedAdapterResponse, adapterResponse); - - for ( var i = 0; i < prebidResponsePair.matched.length; i++) { - var pair = prebidResponsePair.matched[i]; - - for ( var j = 0; j < pair.expected.length; j++ ) { - assert.equal(pair.prebid[j].siteID, pair.expected[j].siteID, "adapter response for " + pair.placementCode + " siteID is set to "+pair.expected[i].siteID); - assert.equal(pair.prebid[j].bidderCode, pair.expected[j].bidderCode, "adapter response for " + pair.placementCode + " bidderCode is set to "+pair.expected[i].bidderCode); - assert.equal(pair.prebid[j].width, pair.expected[j].width, "adapter response for " + pair.placementCode + " width is set to "+pair.expected[i].width); - assert.equal(pair.prebid[j].height, pair.expected[j].height, "adapter response for " + pair.placementCode + " height is set to "+pair.expected[i].height); - assert.equal(pair.prebid[j].ad, pair.expected[j].ad, "adapter response for " + pair.placementCode + " ad is set to "+pair.expected[i].ad); - assert.equal(pair.prebid[j].cpm, pair.expected[j].cpm, "adapter response for " + pair.placementCode + " cpm is set to "+pair.expected[i].cpm); - if ( i === 0) { - assert.equal(pair.prebid[j].dealId, pair.expected[j].dealId, "adapter response for " + pair.placementCode + " deaiid is set to "+pair.expected[i].dealId); - } else { - assert.isUndefined( pair.prebid[j].dealId, "adapter response for " + pair.placementCode + " deaiid is not set"); - } - } - } - - assert.equal( prebidResponsePair.unmatched.expected.length, 0, "All AS bid response translated to Adapter response for prebid"); - assert.equal( prebidResponsePair.unmatched.prebid.length, 0, "All Adapter response for prebid is from AS bid"); - }); - - - it('test_prebid_indexAdapter_response_deal_2_3: response for single slot with multi size, all returned as non-deal response -> all bid fetched, no response has dealID', function () { - var sizeCount = 2; - var configuredBids = IndexUtils.createBidSlots(1, sizeCount); - adapter.callBids({ bids: configuredBids }); - - var requestJSON = IndexUtils.parseIndexRequest(adLoader.loadScript.firstCall.args[0]); - var optionalResponseParam = [ - [ - {}, - {} - // No deal on first slot first size - // No deal on first slot second size - ] - ]; - var asResponse = IndexUtils.getBidResponse( configuredBids, requestJSON, undefined, undefined, undefined, optionalResponseParam ); - - cygnus_index_parse_res( asResponse ); - var expectedAdapterResponse = IndexUtils.getExpectedAdaptorResponse( configuredBids, asResponse ); - - var adapterResponse = {}; - - for ( var i = 0; i < bidManager.addBidResponse.callCount; i++ ) { - var adUnitCode = bidManager.addBidResponse.getCall(i).args[0]; - var bid = bidManager.addBidResponse.getCall(i).args[1]; - - if ( typeof adapterResponse[adUnitCode] === 'undefined'){ - adapterResponse[adUnitCode] = []; - }; - adapterResponse[adUnitCode].push(bid); - } - - var prebidResponsePair = IndexUtils.matchOnPlacementCode(expectedAdapterResponse, adapterResponse); - - for ( var i = 0; i < prebidResponsePair.matched.length; i++) { - var pair = prebidResponsePair.matched[i]; - for ( var j = 0; j < pair.expected.length; j++ ) { - assert.equal(pair.prebid[i].siteID, pair.expected[i].siteID, "adapter response for " + pair.placementCode + " siteID is set to "+pair.expected[i].siteID); - assert.equal(pair.prebid[i].bidderCode, pair.expected[i].bidderCode, "adapter response for " + pair.placementCode + " bidderCode is set to "+pair.expected[i].bidderCode); - assert.equal(pair.prebid[i].width, pair.expected[i].width, "adapter response for " + pair.placementCode + " width is set to "+pair.expected[i].width); - assert.equal(pair.prebid[i].height, pair.expected[i].height, "adapter response for " + pair.placementCode + " height is set to "+pair.expected[i].height); - assert.equal(pair.prebid[i].ad, pair.expected[i].ad, "adapter response for " + pair.placementCode + " ad is set to "+pair.expected[i].ad); - assert.equal(pair.prebid[i].cpm, pair.expected[i].cpm, "adapter response for " + pair.placementCode + " cpm is set to "+pair.expected[i].cpm); - assert.isUndefined( pair.prebid[i].dealId, "adapter response for " + pair.placementCode + " deaiid is not set"); - } - } - assert.equal( prebidResponsePair.unmatched.expected.length, 0, "All AS bid response translated to Adapter response for prebid"); - assert.equal( prebidResponsePair.unmatched.prebid.length, 0, "All Adapter response for prebid is from AS bid"); - }); - - - it('test_prebid_indexAdapter_response_deal_3_1: multi slots, all responses contain deal -> all bid fetched into prebid as deal bid', function () { - var slotCount = 2; - var configuredBids = IndexUtils.createBidSlots(slotCount, 1); - adapter.callBids({ bids: configuredBids }); - - var requestJSON = IndexUtils.parseIndexRequest(adLoader.loadScript.firstCall.args[0]); - var optionalResponseParam = [ - [ - { ext: { dealid: 'ixDeal1' } } // first slot first size - ], - [ - { ext: { dealid: 'ixDeal2' } } // second slot first size - ] - ]; - var asResponse = IndexUtils.getBidResponse( configuredBids, requestJSON, undefined, undefined, undefined, optionalResponseParam ); - cygnus_index_parse_res( asResponse ); - var expectedAdapterResponse = IndexUtils.getExpectedAdaptorResponse( configuredBids, asResponse ); - - var adapterResponse = {}; - - for ( var i = 0; i < bidManager.addBidResponse.callCount; i++ ) { - var adUnitCode = bidManager.addBidResponse.getCall(i).args[0]; - var bid = bidManager.addBidResponse.getCall(i).args[1]; - - if ( typeof adapterResponse[adUnitCode] === 'undefined'){ - adapterResponse[adUnitCode] = []; - }; - adapterResponse[adUnitCode].push(bid); - } - - var prebidResponsePair = IndexUtils.matchOnPlacementCode(expectedAdapterResponse, adapterResponse); - - for ( var i = 0; i < prebidResponsePair.matched.length; i++) { - var pair = prebidResponsePair.matched[i]; - assert.equal(pair.prebid[0].siteID, pair.expected[0].siteID, "adapter response for " + pair.placementCode + " siteID is set to "+pair.expected[0].siteID); - assert.equal(pair.prebid[0].bidderCode, pair.expected[0].bidderCode, "adapter response for " + pair.placementCode + " bidderCode is set to "+pair.expected[0].bidderCode); - assert.equal(pair.prebid[0].width, pair.expected[0].width, "adapter response for " + pair.placementCode + " width is set to "+pair.expected[0].width); - assert.equal(pair.prebid[0].height, pair.expected[0].height, "adapter response for " + pair.placementCode + " height is set to "+pair.expected[0].height); - assert.equal(pair.prebid[0].ad, pair.expected[0].ad, "adapter response for " + pair.placementCode + " ad is set to "+pair.expected[0].ad); - assert.equal(pair.prebid[0].cpm, pair.expected[0].cpm, "adapter response for " + pair.placementCode + " cpm is set to "+pair.expected[0].cpm); - assert.equal(pair.prebid[0].dealId, pair.expected[0].dealId, "adapter response for " + pair.placementCode + " deaiid is set to "+pair.expected[0].dealId); - } - - assert.equal( prebidResponsePair.unmatched.expected.length, 0, "All AS bid response translated to Adapter response for prebid"); - assert.equal( prebidResponsePair.unmatched.prebid.length, 0, "All Adapter response for prebid is from AS bid"); - }); - - - it('test_prebid_indexAdapter_response_deal_3_2: multi slots, some responses contain deal -> all bid fetched, only deal response has dealID', function () { - var slotCount = 2; - var configuredBids = IndexUtils.createBidSlots(slotCount, 1); - adapter.callBids({ bids: configuredBids }); - - var requestJSON = IndexUtils.parseIndexRequest(adLoader.loadScript.firstCall.args[0]); - var optionalResponseParam = [ - [ - { ext: { dealid: 'ixDeal1' } } // first slot first size - ], - [ - {} - // no deal on second slot first size - ] - ]; - var asResponse = IndexUtils.getBidResponse( configuredBids, requestJSON, undefined, undefined, undefined, optionalResponseParam ); - cygnus_index_parse_res( asResponse ); - var expectedAdapterResponse = IndexUtils.getExpectedAdaptorResponse( configuredBids, asResponse ); - - var adapterResponse = {}; - - for ( var i = 0; i < bidManager.addBidResponse.callCount; i++ ) { - var adUnitCode = bidManager.addBidResponse.getCall(i).args[0]; - var bid = bidManager.addBidResponse.getCall(i).args[1]; - - if ( typeof adapterResponse[adUnitCode] === 'undefined'){ - adapterResponse[adUnitCode] = []; - }; - adapterResponse[adUnitCode].push(bid); - } - - var prebidResponsePair = IndexUtils.matchOnPlacementCode(expectedAdapterResponse, adapterResponse); - var count = 0; - for ( var i = 0; i < prebidResponsePair.matched.length; i++) { - var pair = prebidResponsePair.matched[i]; - assert.equal(pair.prebid[0].siteID, pair.expected[0].siteID, "adapter response for " + pair.placementCode + " siteID is set to "+pair.expected[0].siteID); - assert.equal(pair.prebid[0].bidderCode, pair.expected[0].bidderCode, "adapter response for " + pair.placementCode + " bidderCode is set to "+pair.expected[0].bidderCode); - assert.equal(pair.prebid[0].width, pair.expected[0].width, "adapter response for " + pair.placementCode + " width is set to "+pair.expected[0].width); - assert.equal(pair.prebid[0].height, pair.expected[0].height, "adapter response for " + pair.placementCode + " height is set to "+pair.expected[0].height); - assert.equal(pair.prebid[0].ad, pair.expected[0].ad, "adapter response for " + pair.placementCode + " ad is set to "+pair.expected[0].ad); - assert.equal(pair.prebid[0].cpm, pair.expected[0].cpm, "adapter response for " + pair.placementCode + " cpm is set to "+pair.expected[0].cpm); - if ( count === 0 ) { // if first slot, check deal parameter - assert.equal(pair.prebid[0].dealId, pair.expected[0].dealId, "adapter response for " + pair.placementCode + " deaiid is set to "+pair.expected[0].dealId); - } else { - assert.isUndefined( pair.prebid[0].dealId, "adapter response for " + pair.placementCode + " deaiid is not defined"); - } - count ++; - } - - assert.equal( prebidResponsePair.unmatched.expected.length, 0, "All AS bid response translated to Adapter response for prebid"); - assert.equal( prebidResponsePair.unmatched.prebid.length, 0, "All Adapter response for prebid is from AS bid"); - }); - - - it('test_prebid_indexAdapter_response_deal_3_3: multi slots, no responses contain deal -> all bid fetched, no response has dealID ', function () { - var slotCount = 2; - var configuredBids = IndexUtils.createBidSlots(slotCount, 1); - adapter.callBids({ bids: configuredBids }); - - var requestJSON = IndexUtils.parseIndexRequest(adLoader.loadScript.firstCall.args[0]); - var optionalResponseParam = [ - [ - {} - // no deal on first slot first size - ], - [ - {} - // no deal on second slot first size - ] - ]; - var asResponse = IndexUtils.getBidResponse( configuredBids, requestJSON, undefined, undefined, undefined, optionalResponseParam ); - cygnus_index_parse_res( asResponse ); - var expectedAdapterResponse = IndexUtils.getExpectedAdaptorResponse( configuredBids, asResponse ); - - var adapterResponse = {}; - - for ( var i = 0; i < bidManager.addBidResponse.callCount; i++ ) { - var adUnitCode = bidManager.addBidResponse.getCall(i).args[0]; - var bid = bidManager.addBidResponse.getCall(i).args[1]; - - if ( typeof adapterResponse[adUnitCode] === 'undefined'){ - adapterResponse[adUnitCode] = []; - }; - adapterResponse[adUnitCode].push(bid); - } - - var prebidResponsePair = IndexUtils.matchOnPlacementCode(expectedAdapterResponse, adapterResponse); - - for ( var i = 0; i < prebidResponsePair.matched.length; i++) { - var pair = prebidResponsePair.matched[i]; - assert.equal(pair.prebid[0].siteID, pair.expected[0].siteID, "adapter response for " + pair.placementCode + " siteID is set to "+pair.expected[0].siteID); - assert.equal(pair.prebid[0].bidderCode, pair.expected[0].bidderCode, "adapter response for " + pair.placementCode + " bidderCode is set to "+pair.expected[0].bidderCode); - assert.equal(pair.prebid[0].width, pair.expected[0].width, "adapter response for " + pair.placementCode + " width is set to "+pair.expected[0].width); - assert.equal(pair.prebid[0].height, pair.expected[0].height, "adapter response for " + pair.placementCode + " height is set to "+pair.expected[0].height); - assert.equal(pair.prebid[0].ad, pair.expected[0].ad, "adapter response for " + pair.placementCode + " ad is set to "+pair.expected[0].ad); - assert.equal(pair.prebid[0].cpm, pair.expected[0].cpm, "adapter response for " + pair.placementCode + " cpm is set to "+pair.expected[0].cpm); - assert.isUndefined( pair.prebid[0].dealId, "adapter response for " + pair.placementCode + " deaiid is not defined"); - } - - assert.equal( prebidResponsePair.unmatched.expected.length, 0, "All AS bid response translated to Adapter response for prebid"); - assert.equal( prebidResponsePair.unmatched.prebid.length, 0, "All Adapter response for prebid is from AS bid"); - }); - - - it( 'test_prebid_indexAdapter_tier: one slot with multiple tier -> all tier bids are fetched into prebid', function(){ - var slotConfig = { - tier2SiteID: IndexUtils.DefaultSiteID + 1, - tier3SiteID: IndexUtils.DefaultSiteID + 2, - }; - var configuredBids = [ - IndexUtils.createBidSlot( IndexUtils.DefaultPlacementCodePrefix, 'slot_1', [ IndexUtils.supportedSizes[0] ], slotConfig ), - ]; - adapter.callBids({ bids: configuredBids }); - - assert.isTrue(adLoader.loadScript.called, "loadScript get request"); - assert.include(adLoader.loadScript.firstCall.args[0], HeaderTagRequest, "request is headertag request"); - - var requestJSON = IndexUtils.parseIndexRequest(adLoader.loadScript.firstCall.args[0]); - assert.isNotNull( requestJSON.r.imp, "headertag request include impression object" ); - - var impressionObj = requestJSON.r.imp; - var expandedBids = configuredBids.map(bid => IndexUtils.expandSizes(bid)) - var sidMatched = IndexUtils.matchBidsOnSID(expandedBids, impressionObj); - - assert.equal( sidMatched.matched.length, 3, 'Three slots are configured and sent to AS'); - // check normal site id - var normalSitePair = sidMatched.matched[0]; - - var expectedSlotID = normalSitePair.configured.params.id + '_1'; - assert.equal( normalSitePair.sent.ext.sid, expectedSlotID, "request " + normalSitePair.name + " site ID is set to " + expectedSlotID); - assert.isString( normalSitePair.sent.ext.sid, "type of slot ID is string"); - - var expectedSiteID = normalSitePair.configured.params.siteID; - assert.equal(normalSitePair.sent.ext.siteID, expectedSiteID, "request " + normalSitePair.name + " site ID is set to " + expectedSiteID); - assert.isNumber(normalSitePair.sent.ext.siteID, "site ID is integer"); - - // check tier 1 site id - var tier2SitePair = sidMatched.matched[1]; - var expectedTierSlotID = 'T1_' + tier2SitePair.configured.params.id + '_1'; - assert.equal( tier2SitePair.sent.ext.sid, expectedTierSlotID, "request " + tier2SitePair.name + " site ID is set to " + expectedTierSlotID); - assert.isString( tier2SitePair.sent.ext.sid, "type of slot ID is string"); - - var expectedTierSiteID = tier2SitePair.configured.params.tier2SiteID; - assert.equal(tier2SitePair.sent.ext.siteID, expectedTierSiteID, "request " + normalSitePair.name + " site ID is set to " + expectedTierSiteID); - assert.isNumber(tier2SitePair.sent.ext.siteID, "site ID is integer"); - - // check tier 2 site id - var tier3SitePair = sidMatched.matched[2]; - var expectedTierSlotID = 'T2_' + tier3SitePair.configured.params.id + '_1'; - assert.equal( tier3SitePair.sent.ext.sid, expectedTierSlotID, "request " + tier3SitePair.name + " site ID is set to " + expectedTierSlotID); - assert.isString( tier3SitePair.sent.ext.sid, "type of slot ID is string"); - - var expectedTier3SiteID = tier3SitePair.configured.params.tier3SiteID; - assert.equal(tier3SitePair.sent.ext.siteID, expectedTier3SiteID, "request " + normalSitePair.name + " site ID is set to " + expectedTier3SiteID); - assert.isNumber(tier3SitePair.sent.ext.siteID, "site ID is integer"); - - // check unsent bids - assert.equal( sidMatched.unmatched.configured.length, 0, "All configured bids are in impression Obj"); - assert.equal( sidMatched.unmatched.sent.length, 0, "All bids in impression object are from configured bids"); - }); - - it('test_prebid_indexAdapter_callback_bids: callback function defined with bids -> calls callback function with bids', function () { - var callbackCalled = false; - var callback_requestID; - var callback_slots; - window.cygnus_index_args['callback'] = function( requestID, slots ) { - callbackCalled = true; - callback_requestID = requestID; - callback_slots = slots; - } - - var configuredBids = IndexUtils.createBidSlots(1, 1); - adapter.callBids({ bids: configuredBids }); - - var requestJSON = IndexUtils.parseIndexRequest(adLoader.loadScript.firstCall.args[0]); - var asResponse = IndexUtils.getBidResponse( configuredBids, requestJSON ); - cygnus_index_parse_res( asResponse ); - - assert.equal(callbackCalled, true, 'callback function is called'); - assert.equal( callback_requestID, requestJSON.r.id, 'callback requestID matches with actual request ID: ' + requestJSON.r.id ); - assert.equal( callback_slots.length, 1, 'callback slots include one slot'); - }); - - - it('test_prebid_indexAdapter_callback_nobids: callback function defined with no bids -> calls callback function without bids', function () { - var callbackCalled = false; - var callback_requestID; - var callback_slots; - window.cygnus_index_args['callback'] = function( requestID, slots ) { - callbackCalled = true; - callback_requestID = requestID; - callback_slots = slots; - } - - var configuredBids = IndexUtils.createBidSlots(1, 1); - adapter.callBids({ bids: configuredBids }); - - var requestJSON = IndexUtils.parseIndexRequest(adLoader.loadScript.firstCall.args[0]); - var asResponse = IndexUtils.getBidResponse( configuredBids, requestJSON, undefined, undefined, [[true]] ); // pass on bid - cygnus_index_parse_res( asResponse ); - - assert.equal(callbackCalled, true, 'callback function is called'); - assert.equal( callback_requestID, requestJSON.r.id, 'callback requestID matches with actual request ID: ' + requestJSON.r.id ); - assert.isUndefined( callback_slots, 'callback slot is undefined because all bids passed on bid'); - }); - - it('test_prebid_indexAdapter_response_sizeID_1: multiple prebid size slot, index slots with size for all prebid slots -> all size in AS request, no size ID', function () { - var slotID_1 = "52"; - var slotID_2 = "53"; - var slotSizes_1 = IndexUtils.supportedSizes[0]; - var slotSizes_2 = IndexUtils.supportedSizes[1]; - - var configuredBids = [ - IndexUtils.createBidSlot( IndexUtils.DefaultPlacementCodePrefix + slotID_1, slotID_1, [ slotSizes_1, slotSizes_2 ], { slotSize : slotSizes_1 } ), - IndexUtils.createBidSlot( IndexUtils.DefaultPlacementCodePrefix + slotID_2, slotID_2, [ slotSizes_1, slotSizes_2 ], { siteID : IndexUtils.DefaultSiteID + 1 } ) - ]; - - adapter.callBids({ bids: configuredBids }); - - var requestJSON = IndexUtils.parseIndexRequest(adLoader.loadScript.firstCall.args[0]); - var asResponse = IndexUtils.getBidResponse( configuredBids, requestJSON, undefined, undefined, [[true]] ); // pass on bid - cygnus_index_parse_res( asResponse ); - - var adapterResponse = {}; - - for ( var i = 0; i < bidManager.addBidResponse.callCount; i++ ) { - var adUnitCode = bidManager.addBidResponse.getCall(i).args[0]; - var bid = bidManager.addBidResponse.getCall(i).args[1]; - - if ( typeof adapterResponse[adUnitCode] === 'undefined'){ - adapterResponse[adUnitCode] = []; - }; - adapterResponse[adUnitCode].push(bid); - } - }); -}); diff --git a/test/spec/adapters/indexExchange_validation_spec.js b/test/spec/adapters/indexExchange_validation_spec.js deleted file mode 100644 index 9d448b97629..00000000000 --- a/test/spec/adapters/indexExchange_validation_spec.js +++ /dev/null @@ -1,1504 +0,0 @@ -import Adapter from '../../../src/adapters/indexExchange'; -import bidManager from '../../../src/bidmanager'; -import adLoader from '../../../src/adloader'; - -var assert = require('chai').assert; -var IndexUtils = require('../../helpers/index_adapter_utils.js'); -var HeaderTagRequest = '/cygnus'; -var ADAPTER_CODE = 'indexExchange'; - -window.pbjs = window.pbjs || {}; - -describe('indexExchange adapter - Validation', function () { - let adapter; - let sandbox; - - beforeEach( function() { - window._IndexRequestData = {}; - _IndexRequestData.impIDToSlotID = {}; - _IndexRequestData.reqOptions = {}; - _IndexRequestData.targetIDToResp = {}; - window.cygnus_index_args = {}; - - adapter = new Adapter(); - sandbox = sinon.sandbox.create(); - sandbox.stub(adLoader, 'loadScript'); - }); - - afterEach( function() { - sandbox.restore(); - }); - - it('test_prebid_indexAdapter_sizeValidation_1: request slot has supported and unsupported size -> unsupported size ignored in IX demand request', function () { - // create 2 sizes for 1 slot, 1 for supported size, the other is not supported - var unsupportedSize = IndexUtils.unsupportedSizes[0]; - var configuredBids = [ - IndexUtils.createBidSlot( IndexUtils.DefaultPlacementCodePrefix, "slot_1", [ IndexUtils.supportedSizes[0], unsupportedSize ] ) - ]; - - adapter.callBids({ bids: configuredBids }); - - assert.isTrue(adLoader.loadScript.called, "loadScript get request"); - assert.include(adLoader.loadScript.firstCall.args[0], HeaderTagRequest, "request is headertag request"); - - var requestJSON = IndexUtils.parseIndexRequest(adLoader.loadScript.firstCall.args[0]); - assert.isNotNull( requestJSON.r.imp, "headertag request include impression object" ); - - var impressionObj = requestJSON.r.imp; - - var expandedBids = configuredBids.map(bid => IndexUtils.expandSizes(bid)) - var sidMatched = IndexUtils.matchBidsOnSID(expandedBids, impressionObj); - for ( var i = 0; i < sidMatched.matched.length; i++) { - var pair = sidMatched.matched[i]; - - assert.equal(pair.sent.banner.w, pair.configured.size[0], "request " + pair.name + " width is set to " + pair.configured.size[0]); - assert.equal(pair.sent.banner.h, pair.configured.size[1], "request " + pair.name + " width is set to " + pair.configured.size[1]); - assert.equal(pair.sent.ext.siteID, pair.configured.params.siteID, "request " + pair.name + " siteID is set to " + pair.configured.params.siteID); - } - - assert.equal( sidMatched.unmatched.sent.length, 0, "All bids in impression object are from configured bids"); - - assert.equal( sidMatched.unmatched.configured.length, 1, "1 configured bid is not in impression Obj"); - assert.equal( sidMatched.unmatched.configured[0].size, unsupportedSize, "configured bid not in impression obj size width is" + JSON.stringify(unsupportedSize) ); - }); - - it('test_prebid_indexAdapter_sizeValidation_2_1: some slot has unsupported size -> unsupported slot ignored in IX demand request', function () { - // create 2 slot, 1 for supported size, the other is not supported - var unsupportedSize = IndexUtils.unsupportedSizes[0]; - var configuredBids = [ - IndexUtils.createBidSlot( IndexUtils.DefaultPlacementCodePrefix+"supported", "slot_1", [ IndexUtils.supportedSizes[0], ], { siteID:IndexUtils.DefaultSiteID } ), - IndexUtils.createBidSlot( IndexUtils.DefaultPlacementCodePrefix+"unspported", "slot_2", [ unsupportedSize ], { siteID:IndexUtils.DefaultSiteID+1} ) - ]; - - adapter.callBids({ bids: configuredBids }); - - assert.isTrue(adLoader.loadScript.called, "loadScript get request"); - assert.include(adLoader.loadScript.firstCall.args[0], HeaderTagRequest, "request is headertag request"); - - var requestJSON = IndexUtils.parseIndexRequest(adLoader.loadScript.firstCall.args[0]); - assert.isNotNull( requestJSON.r.imp, "headertag request include impression object" ); - - var impressionObj = requestJSON.r.imp; - - var expandedBids = configuredBids.map(bid => IndexUtils.expandSizes(bid)) - var sidMatched = IndexUtils.matchBidsOnSID(expandedBids, impressionObj); - for ( var i = 0; i < sidMatched.matched.length; i++) { - var pair = sidMatched.matched[i]; - - assert.equal(pair.sent.banner.w, pair.configured.size[0], "request " + pair.name + " width is set to " + pair.configured.size[0]); - assert.equal(pair.sent.banner.h, pair.configured.size[1], "request " + pair.name + " width is set to " + pair.configured.size[1]); - assert.equal(pair.sent.ext.siteID, pair.configured.params.siteID, "request " + pair.name + " siteID is set to " + pair.configured.params.siteID); - } - - assert.equal( sidMatched.unmatched.sent.length, 0, "All bids in impression object are from configured bids"); - - assert.equal( sidMatched.unmatched.configured.length, 1, "1 configured bid is not in impression Obj"); - assert.equal( sidMatched.unmatched.configured[0].size, unsupportedSize, "configured bid not in impression obj size width is" + JSON.stringify(unsupportedSize) ); - assert.equal( sidMatched.unmatched.configured[0].params.id, "slot_2", "configured bid not in impression obj id is slot_2" ); - assert.equal( sidMatched.unmatched.configured[0].params.siteID, IndexUtils.DefaultSiteID+1, "configured bid not in impression obj siteID is "+(IndexUtils.DefaultSiteID+1) ); - }); - - it('test_prebid_indexAdapter_sizeValidation_2_2: multiple slots with sinle size, all slot has supported size -> all slots are sent to IX demand', function () { - // create 2 slot, 1 for supported size, the other is not supported - var unsupportedSize = IndexUtils.unsupportedSizes[0]; - var configuredBids = [ - IndexUtils.createBidSlot( IndexUtils.DefaultPlacementCodePrefix+"supported1", "slot_1", [ IndexUtils.supportedSizes[0] ], { siteID:IndexUtils.DefaultSiteID } ), - IndexUtils.createBidSlot( IndexUtils.DefaultPlacementCodePrefix+"supported2", "slot_2", [ IndexUtils.supportedSizes[1] ], { siteID:IndexUtils.DefaultSiteID+1} ) - ]; - - adapter.callBids({ bids: configuredBids }); - - assert.isTrue(adLoader.loadScript.called, "loadScript get request"); - assert.include(adLoader.loadScript.firstCall.args[0], HeaderTagRequest, "request is headertag request"); - - var requestJSON = IndexUtils.parseIndexRequest(adLoader.loadScript.firstCall.args[0]); - assert.isNotNull( requestJSON.r.imp, "headertag request include impression object" ); - - var impressionObj = requestJSON.r.imp; - - var expandedBids = configuredBids.map(bid => IndexUtils.expandSizes(bid)) - var sidMatched = IndexUtils.matchBidsOnSID(expandedBids, impressionObj); - for ( var i = 0; i < sidMatched.matched.length; i++) { - var pair = sidMatched.matched[i]; - - assert.equal(pair.sent.banner.w, pair.configured.size[0], "request " + pair.name + " width is set to " + pair.configured.size[0]); - assert.equal(pair.sent.banner.h, pair.configured.size[1], "request " + pair.name + " width is set to " + pair.configured.size[1]); - assert.equal(pair.sent.ext.siteID, pair.configured.params.siteID, "request " + pair.name + " siteID is set to " + pair.configured.params.siteID); - } - - assert.equal( sidMatched.unmatched.sent.length, 0, "All bids in impression object are from configured bids"); - assert.equal( sidMatched.unmatched.configured.length, 0, "0 configured bid is not in impression Obj"); - }); - - it('test_prebid_indexAdapter_sizeValidation_2_3: multiple slots with sinle size, all slot has unsupported size -> all slots are ignored', function () { - // create 2 slot, 1 for supported size, the other is not supported - var unsupportedSize = IndexUtils.unsupportedSizes[0]; - var configuredBids = [ - IndexUtils.createBidSlot( IndexUtils.DefaultPlacementCodePrefix+"unsupported1", "slot_1", [ IndexUtils.unsupportedSizes[0] ], { siteID:IndexUtils.DefaultSiteID } ), - IndexUtils.createBidSlot( IndexUtils.DefaultPlacementCodePrefix+"unsupported2", "slot_2", [ IndexUtils.unsupportedSizes[1] ], { siteID:IndexUtils.DefaultSiteID+1} ) - ]; - adapter.callBids({ bids: configuredBids }); - - assert.isUndefined( adLoader.loadScript.firstCall.args[0], "no request made to IX demand"); - }); - - it('test_prebid_indexAdapter_sizeValidation_3_1: one slot has supported, unsupported, supported size -> unsupported slot ignored in IX demand request', function () { - // create 2 slot, 1 for supported size, the other is not supported - var unsupportedSize = IndexUtils.unsupportedSizes[0]; - var configuredBids = [ - IndexUtils.createBidSlot( IndexUtils.DefaultPlacementCodePrefix+"somesupported", "slot_1", [ IndexUtils.supportedSizes[0], unsupportedSize ,IndexUtils.supportedSizes[1] ], { siteID:IndexUtils.DefaultSiteID } ), - IndexUtils.createBidSlot( IndexUtils.DefaultPlacementCodePrefix+"allsupported", "slot_2", [ IndexUtils.supportedSizes[2], IndexUtils.supportedSizes[3] ], { siteID:IndexUtils.DefaultSiteID+1} ) - ]; - - adapter.callBids({ bids: configuredBids }); - - assert.isTrue(adLoader.loadScript.called, "loadScript get request"); - assert.include(adLoader.loadScript.firstCall.args[0], HeaderTagRequest, "request is headertag request"); - - var requestJSON = IndexUtils.parseIndexRequest(adLoader.loadScript.firstCall.args[0]); - assert.isNotNull( requestJSON.r.imp, "headertag request include impression object" ); - - var impressionObj = requestJSON.r.imp; - - var expandedBids = configuredBids.map(bid => IndexUtils.expandSizes(bid)) - var sidMatched = IndexUtils.matchBidsOnSize(expandedBids, impressionObj); - for ( var i = 0; i < sidMatched.matched.length; i++) { - var pair = sidMatched.matched[i]; - - assert.equal(pair.sent.banner.w, pair.configured.size[0], "request " + pair.name + " width is set to " + pair.configured.size[0]); - assert.equal(pair.sent.banner.h, pair.configured.size[1], "request " + pair.name + " width is set to " + pair.configured.size[1]); - assert.equal(pair.sent.ext.siteID, pair.configured.params.siteID, "request " + pair.name + " siteID is set to " + pair.configured.params.siteID); - } - - assert.equal( sidMatched.unmatched.sent.length, 0, "All bids in impression object are from configured bids"); - - assert.equal( sidMatched.unmatched.configured.length, 1, "1 configured bid is not in impression Obj"); - assert.equal( sidMatched.unmatched.configured[0].size, unsupportedSize, "configured bid not in impression obj size width is" + JSON.stringify(unsupportedSize) ); - assert.equal( sidMatched.unmatched.configured[0].params.id, "slot_1", "configured bid not in impression obj id is slot_1" ); - assert.equal( sidMatched.unmatched.configured[0].params.siteID, IndexUtils.DefaultSiteID, "configured bid not in impression obj siteID is "+(IndexUtils.DefaultSiteID) ); - }); - - it('test_prebid_indexAdapter_sizeValidation_3_2: one slot has unsupported, supported, unsupported size -> unsupported slot ignored in IX demand request', function () { - // create 2 slot, 1 for supported size, the other is not supported - var unsupportedSize1 = IndexUtils.unsupportedSizes[0]; - var unsupportedSize2 = IndexUtils.unsupportedSizes[1]; - var configuredBids = [ - IndexUtils.createBidSlot( IndexUtils.DefaultPlacementCodePrefix+"somesupported", "slot_1", [ unsupportedSize1, IndexUtils.supportedSizes[1], unsupportedSize2 ], { siteID:IndexUtils.DefaultSiteID } ), - IndexUtils.createBidSlot( IndexUtils.DefaultPlacementCodePrefix+"allsupported", "slot_2", [ IndexUtils.supportedSizes[2], IndexUtils.supportedSizes[3] ], { siteID:IndexUtils.DefaultSiteID+1} ) - ]; - - adapter.callBids({ bids: configuredBids }); - - assert.isTrue(adLoader.loadScript.called, "loadScript get request"); - assert.include(adLoader.loadScript.firstCall.args[0], HeaderTagRequest, "request is headertag request"); - - var requestJSON = IndexUtils.parseIndexRequest(adLoader.loadScript.firstCall.args[0]); - assert.isNotNull( requestJSON.r.imp, "headertag request include impression object" ); - - var impressionObj = requestJSON.r.imp; - - var expandedBids = configuredBids.map(bid => IndexUtils.expandSizes(bid)) - var sidMatched = IndexUtils.matchBidsOnSize(expandedBids, impressionObj); - for ( var i = 0; i < sidMatched.matched.length; i++) { - var pair = sidMatched.matched[i]; - - assert.equal(pair.sent.banner.w, pair.configured.size[0], "request " + pair.name + " width is set to " + pair.configured.size[0]); - assert.equal(pair.sent.banner.h, pair.configured.size[1], "request " + pair.name + " width is set to " + pair.configured.size[1]); - assert.equal(pair.sent.ext.siteID, pair.configured.params.siteID, "request " + pair.name + " siteID is set to " + pair.configured.params.siteID); - } - - assert.equal( sidMatched.unmatched.sent.length, 0, "All bids in impression object are from configured bids"); - - assert.equal( sidMatched.unmatched.configured.length, 2, "2 configured bid is not in impression Obj"); - - assert.equal( sidMatched.unmatched.configured[0].size, unsupportedSize1, "configured bid not in impression obj size width is" + JSON.stringify(unsupportedSize1) ); - assert.equal( sidMatched.unmatched.configured[0].params.id, "slot_1", "configured bid not in impression obj id is slot_1" ); - assert.equal( sidMatched.unmatched.configured[0].params.siteID, IndexUtils.DefaultSiteID, "configured bid not in impression obj siteID is "+(IndexUtils.DefaultSiteID) ); - - assert.equal( sidMatched.unmatched.configured[1].size, unsupportedSize2, "configured bid not in impression obj size width is" + JSON.stringify(unsupportedSize2) ); - assert.equal( sidMatched.unmatched.configured[1].params.id, "slot_1", "configured bid not in impression obj id is slot_1" ); - assert.equal( sidMatched.unmatched.configured[1].params.siteID, IndexUtils.DefaultSiteID, "configured bid not in impression obj siteID is "+(IndexUtils.DefaultSiteID) ); - }); - - it('test_prebid_indexAdapter_sizeValidation_3_3: multiple slots, all slots have supported size -> all slots are included in IX demand request', function () { - var configuredBids = [ - IndexUtils.createBidSlot( IndexUtils.DefaultPlacementCodePrefix+"allsupported1", "slot_1", [ IndexUtils.supportedSizes[0], IndexUtils.supportedSizes[1] ], { siteID:IndexUtils.DefaultSiteID } ), - IndexUtils.createBidSlot( IndexUtils.DefaultPlacementCodePrefix+"allsupported2", "slot_2", [ IndexUtils.supportedSizes[2], IndexUtils.supportedSizes[3] ], { siteID:IndexUtils.DefaultSiteID+1} ) - ]; - - adapter.callBids({ bids: configuredBids }); - - assert.isTrue(adLoader.loadScript.called, "loadScript get request"); - assert.include(adLoader.loadScript.firstCall.args[0], HeaderTagRequest, "request is headertag request"); - - var requestJSON = IndexUtils.parseIndexRequest(adLoader.loadScript.firstCall.args[0]); - assert.isNotNull( requestJSON.r.imp, "headertag request include impression object" ); - - var impressionObj = requestJSON.r.imp; - - var expandedBids = configuredBids.map(bid => IndexUtils.expandSizes(bid)) - var sidMatched = IndexUtils.matchBidsOnSize(expandedBids, impressionObj); - for ( var i = 0; i < sidMatched.matched.length; i++) { - var pair = sidMatched.matched[i]; - - assert.equal(pair.sent.banner.w, pair.configured.size[0], "request " + pair.name + " width is set to " + pair.configured.size[0]); - assert.equal(pair.sent.banner.h, pair.configured.size[1], "request " + pair.name + " width is set to " + pair.configured.size[1]); - assert.equal(pair.sent.ext.siteID, pair.configured.params.siteID, "request " + pair.name + " siteID is set to " + pair.configured.params.siteID); - } - - assert.equal( sidMatched.unmatched.sent.length, 0, "All bids in impression object are from configured bids"); - - assert.equal( sidMatched.unmatched.configured.length, 0, "0 configured bid is not in impression Obj"); - }); - - it('test_prebid_indexAdapter_sizeValidation_3_4: multiple slots, all slots have unsupported size -> no slots are sent to IX demand', function () { - var configuredBids = [ - IndexUtils.createBidSlot( IndexUtils.DefaultPlacementCodePrefix+"allsupported1", "slot_1", [ IndexUtils.unsupportedSizes[0], IndexUtils.unsupportedSizes[1] ], { siteID:IndexUtils.DefaultSiteID } ), - IndexUtils.createBidSlot( IndexUtils.DefaultPlacementCodePrefix+"allsupported2", "slot_2", [ IndexUtils.unsupportedSizes[2], IndexUtils.unsupportedSizes[3] ], { siteID:IndexUtils.DefaultSiteID+1} ) - ]; - adapter.callBids({ bids: configuredBids }); - - assert.isUndefined(adLoader.loadScript.firstCall.args[0], "No request to IX demand"); - }); - - it('test_prebid_indexAdapter_param_timeout_integer: timeout is integer -> t parameter that matches with the integer', function () { - var testTimeout = 100; // integer timeout - var configuredBids = [ - IndexUtils.createBidSlot( IndexUtils.DefaultPlacementCodePrefix, "slot_1", [ IndexUtils.supportedSizes[0] ], { timeout: testTimeout } ), - ]; - adapter.callBids({ bids: configuredBids }); - - assert.isTrue(adLoader.loadScript.called, "loadScript get request"); - assert.include(adLoader.loadScript.firstCall.args[0], HeaderTagRequest, "request is headertag request"); - - var requestJSON = IndexUtils.parseIndexRequest(adLoader.loadScript.firstCall.args[0]); - assert.equal( requestJSON.t, testTimeout, 't parameter matches timeout and is included in AS request parameter' ); - }); - - it('test_prebid_indexAdapter_param_timeout_quoted_integer: timeout is quoted integer -> t parameter that matches with the integer', function () { - var testTimeout = '100'; // quoted integer timeout - var configuredBids = [ - IndexUtils.createBidSlot( IndexUtils.DefaultPlacementCodePrefix, "slot_1", [ IndexUtils.supportedSizes[0] ], { timeout: testTimeout } ), - ]; - adapter.callBids({ bids: configuredBids }); - - assert.isTrue(adLoader.loadScript.called, "loadScript get request"); - assert.include(adLoader.loadScript.firstCall.args[0], HeaderTagRequest, "request is headertag request"); - - var requestJSON = IndexUtils.parseIndexRequest(adLoader.loadScript.firstCall.args[0]); - assert.equal( requestJSON.t, testTimeout, 't parameter matches timeout and is included in AS request parameter' ); - }); - - it('test_prebid_indexAdapter_param_timeout_float: timeout is float number -> t parameter is not included in AS request', function () { - var testTimeout = 1.234; - var configuredBids = [ - IndexUtils.createBidSlot( IndexUtils.DefaultPlacementCodePrefix, "slot_1", [ IndexUtils.supportedSizes[0] ], { timeout: testTimeout } ), - ]; - adapter.callBids({ bids: configuredBids }); - - assert.isTrue(adLoader.loadScript.called, "loadScript get request"); - assert.include(adLoader.loadScript.firstCall.args[0], HeaderTagRequest, "request is headertag request"); - - var requestJSON = IndexUtils.parseIndexRequest(adLoader.loadScript.firstCall.args[0]); - assert.isUndefined( requestJSON.t, 't parameter is not included in AS request parameter' ); - }); - - it('test_prebid_indexAdapter_param_timeout_float: timeout is float number -> t parameter is not included in AS request', function () { - var testTimeout = 1.234; - var configuredBids = [ - IndexUtils.createBidSlot( IndexUtils.DefaultPlacementCodePrefix, "slot_1", [ IndexUtils.supportedSizes[0] ], { timeout: testTimeout } ), - ]; - adapter.callBids({ bids: configuredBids }); - - assert.isTrue(adLoader.loadScript.called, "loadScript get request"); - assert.include(adLoader.loadScript.firstCall.args[0], HeaderTagRequest, "request is headertag request"); - - var requestJSON = IndexUtils.parseIndexRequest(adLoader.loadScript.firstCall.args[0]); - assert.isUndefined( requestJSON.t, 't parameter is not included in AS request parameter' ); - }); - - it('test_prebid_indexAdapter_param_timeout_string: timeout is string -> t parameter is not included in AS request', function () { - var testTimeout = 'string'; - var configuredBids = [ - IndexUtils.createBidSlot( IndexUtils.DefaultPlacementCodePrefix, "slot_1", [ IndexUtils.supportedSizes[0] ], { timeout: testTimeout } ), - ]; - adapter.callBids({ bids: configuredBids }); - - assert.isTrue(adLoader.loadScript.called, "loadScript get request"); - assert.include(adLoader.loadScript.firstCall.args[0], HeaderTagRequest, "request is headertag request"); - - var requestJSON = IndexUtils.parseIndexRequest(adLoader.loadScript.firstCall.args[0]); - assert.isUndefined( requestJSON.t, 't parameter is not included in AS request parameter' ); - }); - - it('test_prebid_indexAdapter_param_timeout_array: timeout is array -> t parameter is not included in AS request', function () { - var testTimeout = [ 'abc' ]; - var configuredBids = [ - IndexUtils.createBidSlot( IndexUtils.DefaultPlacementCodePrefix, "slot_1", [ IndexUtils.supportedSizes[0] ], { timeout: testTimeout } ), - ]; - adapter.callBids({ bids: configuredBids }); - - assert.isTrue(adLoader.loadScript.called, "loadScript get request"); - assert.include(adLoader.loadScript.firstCall.args[0], HeaderTagRequest, "request is headertag request"); - - var requestJSON = IndexUtils.parseIndexRequest(adLoader.loadScript.firstCall.args[0]); - assert.isUndefined( requestJSON.t, 't parameter is not included in AS request parameter' ); - }); - - it('test_prebid_indexAdapter_param_timeout_hash: timeout is hash -> t parameter is not included in AS request', function () { - var testTimeout = { 'timeout': 100 }; - var configuredBids = [ - IndexUtils.createBidSlot( IndexUtils.DefaultPlacementCodePrefix, "slot_1", [ IndexUtils.supportedSizes[0] ], { timeout: testTimeout } ), - ]; - adapter.callBids({ bids: configuredBids }); - - assert.isTrue(adLoader.loadScript.called, "loadScript get request"); - assert.include(adLoader.loadScript.firstCall.args[0], HeaderTagRequest, "request is headertag request"); - - var requestJSON = IndexUtils.parseIndexRequest(adLoader.loadScript.firstCall.args[0]); - assert.isUndefined( requestJSON.t, 't parameter is not included in AS request parameter' ); - }); - - it('test_prebid_indexAdapter_param_timeout_zero: timeout is zero -> t parameter is not included in AS request', function () { - var testTimeout = 0; - var configuredBids = [ - IndexUtils.createBidSlot( IndexUtils.DefaultPlacementCodePrefix, "slot_1", [ IndexUtils.supportedSizes[0] ], { timeout: testTimeout } ), - ]; - adapter.callBids({ bids: configuredBids }); - - assert.isTrue(adLoader.loadScript.called, "loadScript get request"); - assert.include(adLoader.loadScript.firstCall.args[0], HeaderTagRequest, "request is headertag request"); - - var requestJSON = IndexUtils.parseIndexRequest(adLoader.loadScript.firstCall.args[0]); - assert.isUndefined( requestJSON.t, 't parameter is not included in AS request parameter' ); - }); - - it('test_prebid_indexAdapter_param_timeout_negative: timeout is negative integer -> t parameter is not included in AS request', function () { - var testTimeout = -100; - var configuredBids = [ - IndexUtils.createBidSlot( IndexUtils.DefaultPlacementCodePrefix, "slot_1", [ IndexUtils.supportedSizes[0] ], { timeout: testTimeout } ), - ]; - adapter.callBids({ bids: configuredBids }); - - assert.isTrue(adLoader.loadScript.called, "loadScript get request"); - assert.include(adLoader.loadScript.firstCall.args[0], HeaderTagRequest, "request is headertag request"); - - var requestJSON = IndexUtils.parseIndexRequest(adLoader.loadScript.firstCall.args[0]); - assert.isUndefined( requestJSON.t, 't parameter is not included in AS request parameter' ); - }); - - it('test_prebid_indexAdapter_param_timeout_too_big: timeout is bigger than AS max timeout -> t parameter is not included in AS request', function () { - var testTimeout = 25000; // very large timeout - var configuredBids = [ - IndexUtils.createBidSlot( IndexUtils.DefaultPlacementCodePrefix, "slot_1", [ IndexUtils.supportedSizes[0] ], { timeout: testTimeout } ), - ]; - adapter.callBids({ bids: configuredBids }); - - assert.isTrue(adLoader.loadScript.called, "loadScript get request"); - assert.include(adLoader.loadScript.firstCall.args[0], HeaderTagRequest, "request is headertag request"); - - var requestJSON = IndexUtils.parseIndexRequest(adLoader.loadScript.firstCall.args[0]); - assert.equal( requestJSON.t, testTimeout, 't parameter matches timeout and is included in AS request parameter' ); - }); - - it('test_prebid_indexAdapter_param_timeout_missing: timeout is missing -> t parameter is not included in AS request', function () { - var configuredBids = [ - IndexUtils.createBidSlot( IndexUtils.DefaultPlacementCodePrefix, "slot_1", [ IndexUtils.supportedSizes[0] ] ), - ]; - adapter.callBids({ bids: configuredBids }); - - assert.isTrue(adLoader.loadScript.called, "loadScript get request"); - assert.include(adLoader.loadScript.firstCall.args[0], HeaderTagRequest, "request is headertag request"); - - var requestJSON = IndexUtils.parseIndexRequest(adLoader.loadScript.firstCall.args[0]); - assert.isUndefined( requestJSON.t, 't parameter is not included in AS request parameter' ); - }); - - it('test_prebid_indexAdapter_param_timeout_empty_string: timeout is empty string -> t parameter is not included in AS request', function () { - var testTimeout = ''; - var configuredBids = [ - IndexUtils.createBidSlot( IndexUtils.DefaultPlacementCodePrefix, "slot_1", [ IndexUtils.supportedSizes[0] ], { timeout: testTimeout} ), - ]; - adapter.callBids({ bids: configuredBids }); - - assert.isTrue(adLoader.loadScript.called, "loadScript get request"); - assert.include(adLoader.loadScript.firstCall.args[0], HeaderTagRequest, "request is headertag request"); - - var requestJSON = IndexUtils.parseIndexRequest(adLoader.loadScript.firstCall.args[0]); - assert.isUndefined( requestJSON.t, 't parameter is not included in AS request parameter' ); - }); - - var test_indexAdapter_slotid = [ - { - 'testname' : 'test_prebid_indexAdapter_slotid_integer: slot ID is integer -> slot ID sent to AS in string', - 'slotID' : 123, - 'expected' : 'pass' - }, - { - 'testname' : 'test_prebid_indexAdapter_slotid_quoted_integer: slot ID is quoted_integer -> slot ID sent to AS in string', - 'slotID' : '123', - 'expected' : 'pass' - }, - { - 'testname' : 'test_prebid_indexAdapter_slotid_float: slot ID is float -> slot ID sent to AS in string', - 'slotID' : 123.45, - 'expected' : 'pass' - }, - { - 'testname' : 'test_prebid_indexAdapter_slotid_string: slot ID is string -> slot ID sent to AS in string', - 'slotID' : 'string', - 'expected' : 'pass' - }, - { - 'testname' : 'test_prebid_indexAdapter_slotid_array: slot ID is array -> slot is not sent to AS', - 'slotID' : [ 'arrayelement1', 'arrayelement2' ], - 'expected' : 'fail' - }, - { - 'testname' : 'test_prebid_indexAdapter_slotid_hash: slot ID is hash -> slot is not sent to AS', - 'slotID' : { "hashName": "hashKey" }, - 'expected' : 'fail' - }, - { - 'testname' : 'test_prebid_indexAdapter_slotid_zero: slot ID is zero integer -> slot ID sent to AS in string', - 'slotID' : 0, - 'expected' : 'pass' - }, - { - 'testname' : 'test_prebid_indexAdapter_slotid_negative: slot ID is negative integer -> slot ID sent to AS in string', - 'slotID' : -100, - 'expected' : 'pass' - }, - { - 'testname' : 'test_prebid_indexAdapter_slotid_undefined: slot ID is undefined -> slot is not sent to AS', - 'slotID' : undefined, - 'expected' : 'fail' - }, - { - 'testname' : 'test_prebid_indexAdapter_slotid_missing: slot ID is missing -> slot is not sent to AS', - 'param' : { 'missingSlotID': true}, - 'expected' : 'invalid' - } - ]; - - function base_prebid_indexAdapter_slotid ( testname, slotID, expected, param ) { - it( testname, function(){ - var configuredBids = [ - IndexUtils.createBidSlot( IndexUtils.DefaultPlacementCodePrefix, slotID, [ IndexUtils.supportedSizes[0] ], param ), - ]; - adapter.callBids({ bids: configuredBids }); - if ( expected == 'pass' ) { - assert.isTrue(adLoader.loadScript.called, "loadScript get request"); - assert.include(adLoader.loadScript.firstCall.args[0], HeaderTagRequest, "request is headertag request"); - - var requestJSON = IndexUtils.parseIndexRequest(adLoader.loadScript.firstCall.args[0]); - assert.isNotNull( requestJSON.r.imp, "headertag request include impression object" ); - - var impressionObj = requestJSON.r.imp; - - var expandedBids = configuredBids.map(bid => IndexUtils.expandSizes(bid)) - var sidMatched = IndexUtils.matchBidsOnSID(expandedBids, impressionObj); - for ( var i = 0; i < sidMatched.matched.length; i++) { - var pair = sidMatched.matched[i]; - - var actualSlotID = pair.sent.ext.sid; - var expectedSlotID = pair.configured.params.id + '_1'; - assert.equal(actualSlotID, expectedSlotID, "request " + pair.name + " slot ID is set to " + expectedSlotID); - assert.isString(actualSlotID, "slotID is string"); - } - - assert.equal( sidMatched.unmatched.configured.length, 0, "All configured bids are in impression Obj"); - assert.equal( sidMatched.unmatched.sent.length, 0, "All bids in impression object are from configured bids"); - } else if (expected == 'invalid'){ - //case where callBids throws out request due to missing params - assert.isFalse(adLoader.loadScript.called, 'No request to AS') - } else { - assert.strictEqual(typeof indexBidRequest, 'undefined', 'No request to AS'); - } - }); - }; - - for ( var i=0; i < test_indexAdapter_slotid.length; i++ ){ - var test = test_indexAdapter_slotid[i]; - base_prebid_indexAdapter_slotid( test.testname, test.slotID, test.expected, test.param ); - } - - - it( 'test_prebid_indexAdapter_slotid_multiple_slot: uniqueness for multiple slots -> all slots in ad server request with unique slot id', function(){ - var configuredBids = [ - IndexUtils.createBidSlot( IndexUtils.DefaultPlacementCodePrefix, 'slot_1', [ IndexUtils.supportedSizes[0] ] ), - IndexUtils.createBidSlot( IndexUtils.DefaultPlacementCodePrefix, 'slot_2', [ IndexUtils.supportedSizes[1] ] ), - ]; - adapter.callBids({ bids: configuredBids }); - assert.isTrue(adLoader.loadScript.called, "loadScript get request"); - - assert.include(adLoader.loadScript.firstCall.args[0], HeaderTagRequest, "request is headertag request"); - - var requestJSON = IndexUtils.parseIndexRequest(adLoader.loadScript.firstCall.args[0]); - assert.isNotNull( requestJSON.r.imp, "headertag request include impression object" ); - - var impressionObj = requestJSON.r.imp; - - var expandedBids = configuredBids.map(bid => IndexUtils.expandSizes(bid)) - var sidMatched = IndexUtils.matchBidsOnSID(expandedBids, impressionObj); - for ( var i = 0; i < sidMatched.matched.length; i++) { - var pair = sidMatched.matched[i]; - - var actualSlotID = pair.sent.ext.sid; - var expectedSlotID = pair.configured.params.id + '_1'; - assert.equal(actualSlotID, expectedSlotID, "request " + pair.name + " slot ID is set to " + expectedSlotID); - assert.isString(actualSlotID, "slotID is string"); - } - - assert.equal( sidMatched.unmatched.configured.length, 0, "All configured bids are in impression Obj"); - assert.equal( sidMatched.unmatched.sent.length, 0, "All bids in impression object are from configured bids"); - }); - - it( 'test_prebid_indexAdapter_slotid_multiple_same: same across some slots -> all slots in ad server request with same slot id', function(){ - var slotName = 'slot_same'; - var secondSlotSize = IndexUtils.supportedSizes[1]; - var configuredBids = [ - IndexUtils.createBidSlot( IndexUtils.DefaultPlacementCodePrefix, slotName, [ IndexUtils.supportedSizes[0] ] ), - IndexUtils.createBidSlot( IndexUtils.DefaultPlacementCodePrefix, slotName, [ secondSlotSize ] ), - ]; - adapter.callBids({ bids: configuredBids }); - assert.isTrue(adLoader.loadScript.called, "loadScript get request"); - assert.include(adLoader.loadScript.firstCall.args[0], HeaderTagRequest, "request is headertag request"); - - var requestJSON = IndexUtils.parseIndexRequest(adLoader.loadScript.firstCall.args[0]); - assert.isNotNull( requestJSON.r.imp, "headertag request include impression object" ); - - var impressionObj = requestJSON.r.imp; - - var expandedBids = configuredBids.map(bid => IndexUtils.expandSizes(bid)) - var sidMatched = IndexUtils.matchBidsOnSize(expandedBids, impressionObj); - for ( var i = 0; i < sidMatched.matched.length; i++) { - var pair = sidMatched.matched[i]; - - var actualSlotID = pair.sent.ext.sid; - var expectedSlotID = pair.configured.params.id + '_1'; - assert.equal(actualSlotID, expectedSlotID, "request " + pair.name + " slot ID is set to " + expectedSlotID); - assert.isString(actualSlotID, "slotID is string"); - } - - assert.equal( sidMatched.unmatched.sent.length, 0, "All bids in impression object are from configured bids"); - - assert.equal( sidMatched.unmatched.configured.length, 1, "All configured bids are in impression Obj"); - assert.equal( sidMatched.unmatched.configured[0].size, secondSlotSize, "configured bid not in impression obj size width is" + JSON.stringify(secondSlotSize) ); - assert.equal( sidMatched.unmatched.configured[0].params.id, slotName, "slot name is " + slotName ); - }); - - var test_indexAdapter_siteid = [ - { - 'testname' : 'test_prebid_indexAdapter_siteid_integer: site ID is integer -> siteID ID sent to AS as integer', - 'param' : { 'siteID': 12345 }, - 'expected' : 'pass', - }, - { - 'testname' : 'test_prebid_indexAdapter_siteid_quoted_integer: site ID is quoted integer -> siteID ID sent to AS as integer', - 'param' : { 'siteID': '12345' }, - 'expected' : 'pass', - }, - { - 'testname' : 'test_prebid_indexAdapter_siteid_float: site ID is float -> slot is ignored', - 'param' : { 'siteID': 12.345 }, - 'expected' : 'fail', - }, - { - 'testname' : 'test_prebid_indexAdapter_siteid_string: site ID is string -> slot is ignored', - 'param' : { 'siteID': 'string' }, - 'expected' : 'fail', - }, - { - 'testname' : 'test_prebid_indexAdapter_siteid_array: site ID is array with int -> siteID sent to AS as integer', - 'param' : { 'siteID': [ 12345 ] }, - 'expected' : 'pass', - }, - { - 'testname' : 'test_prebid_indexAdapter_siteid_array: site ID is array with quoted int -> siteID sent to AS as integer', - 'param' : { 'siteID': [ "12345" ] }, - 'expected' : 'pass', - }, - { - 'testname' : 'test_prebid_indexAdapter_siteid_array: site ID is array with alpha string -> slot is ignored', - 'param' : { 'siteID': [ "ABC" ] }, - 'expected' : 'fail', - }, - { - 'testname' : 'test_prebid_indexAdapter_siteid_hash: site ID is hash -> slot is ignored', - 'param' : { 'siteID': { 12345: 678 } }, - 'expected' : 'fail', - }, - { - 'testname' : 'test_prebid_indexAdapter_siteid_zero: site ID is zero integer -> slot is ignored', - 'param' : { 'siteID': 0 }, - 'expected' : 'fail', - }, - { - 'testname' : 'test_prebid_indexAdapter_siteid_negative: site ID is a negative integer -> slot is ignored', - 'param' : { 'siteID': -1234 }, - 'expected' : 'fail', - }, - { - 'testname' : 'test_prebid_indexAdapter_siteid_missing: site ID is missing -> slot is ignored', - 'param' : { 'missingSiteID': true }, - 'expected' : 'invalid', - }, - ]; - - function base_prebid_indexAdapter_siteid ( testname, param, expected ) { - it( testname, function(){ - var configuredBids = [ - IndexUtils.createBidSlot( IndexUtils.DefaultPlacementCodePrefix, 'slot_1', [ IndexUtils.supportedSizes[0] ], param ), - ]; - - adapter.callBids({ bids: configuredBids }); - if ( expected == 'pass' ) { - assert.isTrue(adLoader.loadScript.called, "loadScript get request"); - assert.include(adLoader.loadScript.firstCall.args[0], HeaderTagRequest, "request is headertag request"); - - var requestJSON = IndexUtils.parseIndexRequest(adLoader.loadScript.firstCall.args[0]); - assert.isNotNull( requestJSON.r.imp, "headertag request include impression object" ); - - var impressionObj = requestJSON.r.imp; - - var expandedBids = configuredBids.map(bid => IndexUtils.expandSizes(bid)) - var sidMatched = IndexUtils.matchBidsOnSID(expandedBids, impressionObj); - for ( var i = 0; i < sidMatched.matched.length; i++) { - var pair = sidMatched.matched[i]; - - var actualSiteID = pair.sent.ext.siteID; - var expectedSiteID = pair.configured.params.siteID; - assert.equal(actualSiteID, expectedSiteID, "request " + pair.name + " site ID is set to " + expectedSiteID); - assert.isNumber(actualSiteID, "site ID is integer"); - } - - assert.equal( sidMatched.unmatched.configured.length, 0, "All configured bids are in impression Obj"); - assert.equal( sidMatched.unmatched.sent.length, 0, "All bids in impression object are from configured bids"); - } else if (expected == 'invalid') { - //case where callBids throws out request due to missing params - assert.isFalse(adLoader.loadScript.called, 'No request to AS'); - } else { - assert.isUndefined(adLoader.loadScript.firstCall.args[0], 'No request to AS'); - } - }); - }; - - for ( var i=0; i < test_indexAdapter_siteid.length; i++ ){ - var test = test_indexAdapter_siteid[i]; - base_prebid_indexAdapter_siteid( test.testname, test.param, test.expected ); - } - - // TS: case created by PBA-12 - it( 'test_prebid_indexAdapter_second_siteid_float: site ID is float -> slot is ignored', function(){ - var configuredBids = [ - IndexUtils.createBidSlot( IndexUtils.DefaultPlacementCodePrefix+'1', 'slot_1', [ IndexUtils.supportedSizes[0] ] ), - IndexUtils.createBidSlot( IndexUtils.DefaultPlacementCodePrefix+'2', 'slot_2', [ IndexUtils.supportedSizes[1] ], { 'siteID': 123.45 } ), - ]; - - adapter.callBids({ bids: configuredBids }); - - assert.isTrue(adLoader.loadScript.called, "loadScript get request"); - assert.include(adLoader.loadScript.firstCall.args[0], HeaderTagRequest, "request is headertag request"); - - var requestJSON = IndexUtils.parseIndexRequest(adLoader.loadScript.firstCall.args[0]); - assert.isNotNull( requestJSON.r.imp, "headertag request include impression object" ); - - var impressionObj = requestJSON.r.imp; - - var expandedBids = configuredBids.map(bid => IndexUtils.expandSizes(bid)) - var sidMatched = IndexUtils.matchBidsOnSID(expandedBids, impressionObj); - assert.equal( sidMatched.matched.length, 1, 'one slot is configured and sent to AS'); - - for ( var i = 0; i < sidMatched.matched.length; i++) { - var pair = sidMatched.matched[i]; - - var actualSiteID = pair.sent.ext.siteID; - var expectedSiteID = pair.configured.params.siteID; - assert.equal(actualSiteID, expectedSiteID, "request " + pair.name + " site ID is set to " + expectedSiteID); - assert.isNumber(actualSiteID, "site ID is integer"); - } - - assert.equal( sidMatched.unmatched.configured.length, 1, "float site ID configured bid is missing in impression Obj"); - assert.equal( sidMatched.unmatched.sent.length, 0, "All bids in impression object are from configured bids"); - }); - - - var test_indexAdapter_tier2siteid = [ - { - 'testname' : 'test_prebid_indexAdapter_tier2siteid_integer: tier2 site ID is integer -> siteID ID sent to AS in integer', - 'param' : { 'tier2SiteID': 12345 }, - 'expected' : 'pass', - }, - { - 'testname' : 'test_prebid_indexAdapter_tier2siteid_quoted_integer: tier2 site ID is quoted integer -> siteID ID sent to AS in integer', - 'param' : { 'tier2SiteID': '12345' }, - 'expected' : 'pass', - }, - { - 'testname' : 'test_prebid_indexAdapter_tier2siteid_float: tier2 site ID is float -> slot is ignored', - 'param' : { 'tier2SiteID': 12.345 }, - 'expected' : 'fail', - }, - { - 'testname' : 'test_prebid_indexAdapter_tier2siteid_string: tier2 site ID is string -> slot is ignored', - 'param' : { 'tier2SiteID': 'string' }, - 'expected' : 'fail', - }, - { - 'testname' : 'test_prebid_indexAdapter_tier2siteid_array: tier2 site ID is array -> slot is ignored', - 'param' : { 'tier2SiteID': [ 12345 ] }, - 'expected' : 'pass', - }, - { - 'testname' : 'test_prebid_indexAdapter_tier2siteid_hash: tier2 site ID is hash -> slot is ignored', - 'param' : { 'tier2SiteID': { 12345: 678 } }, - 'expected' : 'fail', - }, - { - 'testname' : 'test_prebid_indexAdapter_tier2siteid_zero: tier2 site ID is zero integer -> slot is ignored', - 'param' : { 'tier2SiteID': 0 }, - 'expected' : 'fail', - }, - { - 'testname' : 'test_prebid_indexAdapter_tier2siteid_negative: tier2 site ID is a negative integer -> slot is ignored', - 'param' : { 'tier2SiteID': -1234 }, - 'expected' : 'fail', - }, - { - 'testname' : 'test_prebid_indexAdapter_tier2siteid_missing: tier2 site ID is missing -> slot is ignored', - 'param' : { 'missingtier2SiteID': true }, - 'expected' : 'fail', - }, - ]; - function base_prebid_indexAdapter_tier2siteid ( testname, param, expected ) { - it( testname, function(){ - var configuredBids = [ - IndexUtils.createBidSlot( IndexUtils.DefaultPlacementCodePrefix, 'slot_1', [ IndexUtils.supportedSizes[0] ], param ), - ]; - adapter.callBids({ bids: configuredBids }); - - assert.isTrue(adLoader.loadScript.called, "loadScript get request"); - assert.include(adLoader.loadScript.firstCall.args[0], HeaderTagRequest, "request is headertag request"); - - var requestJSON = IndexUtils.parseIndexRequest(adLoader.loadScript.firstCall.args[0]); - assert.isNotNull( requestJSON.r.imp, "headertag request include impression object" ); - - var impressionObj = requestJSON.r.imp; - var expandedBids = configuredBids.map(bid => IndexUtils.expandSizes(bid)) - var sidMatched = IndexUtils.matchBidsOnSID(expandedBids, impressionObj); - - if ( expected == 'pass' ) { - assert.equal( sidMatched.matched.length, 2, 'Two slots are configured and sent to AS'); - - // check normal site id - var normalSitePair = sidMatched.matched[0]; - - var expectedSlotID = normalSitePair.configured.params.id + '_1'; - assert.equal( normalSitePair.sent.ext.sid, expectedSlotID, "request " + normalSitePair.name + " site ID is set to " + expectedSlotID); - assert.isString( normalSitePair.sent.ext.sid, "type of slot ID is string"); - - var expectedSiteID = normalSitePair.configured.params.siteID; - assert.equal(normalSitePair.sent.ext.siteID, expectedSiteID, "request " + normalSitePair.name + " site ID is set to " + expectedSiteID); - assert.isNumber(normalSitePair.sent.ext.siteID, "site ID is integer"); - - // check tier site id - var tier2SitePair = sidMatched.matched[1]; - var expectedTierSlotID = 'T1_' + tier2SitePair.configured.params.id + '_1'; - assert.equal( tier2SitePair.sent.ext.sid, expectedTierSlotID, "request " + tier2SitePair.name + " site ID is set to " + expectedTierSlotID); - assert.isString( tier2SitePair.sent.ext.sid, "type of slot ID is string"); - - var expectedTierSiteID = tier2SitePair.configured.params.tier2SiteID; - assert.equal(tier2SitePair.sent.ext.siteID, expectedTierSiteID, "request " + normalSitePair.name + " site ID is set to " + expectedTierSiteID); - assert.isNumber(tier2SitePair.sent.ext.siteID, "site ID is integer"); - - // check unsent bids - assert.equal( sidMatched.unmatched.configured.length, 0, "All configured bids are in impression Obj"); - assert.equal( sidMatched.unmatched.sent.length, 0, "All bids in impression object are from configured bids"); - } else { - assert.equal( sidMatched.matched.length, 1, 'one slot is configured and sent to AS'); - - // check normal site id - var normalSitePair = sidMatched.matched[0]; - - var expectedSlotID = normalSitePair.configured.params.id + '_1'; - assert.equal( normalSitePair.sent.ext.sid, expectedSlotID, "request " + normalSitePair.name + " site ID is set to " + expectedSlotID); - assert.isString( normalSitePair.sent.ext.sid, "type of slot ID is string"); - - var expectedSiteID = normalSitePair.configured.params.siteID; - assert.equal(normalSitePair.sent.ext.siteID, expectedSiteID, "request " + normalSitePair.name + " site ID is set to " + expectedSiteID); - assert.isNumber(normalSitePair.sent.ext.siteID, "site ID is integer"); - - // check unsent bids - if ( param.missingtier2SiteID ){ - assert.equal( sidMatched.unmatched.configured.length, 0, "one configured bid is missing in impression Obj"); - } else { - assert.equal( sidMatched.unmatched.configured.length, 1, "one configured bid is missing in impression Obj"); - } - assert.equal( sidMatched.unmatched.sent.length, 0, "All bids in impression object are from configured bids"); - } - }); - }; - - for ( var i=0; i < test_indexAdapter_tier2siteid.length; i++ ){ - var test = test_indexAdapter_tier2siteid[i]; - base_prebid_indexAdapter_tier2siteid( test.testname, test.param, test.expected ); - } - - var test_indexAdapter_tier3siteid = [ - { - 'testname' : 'test_prebid_indexAdapter_tier3siteid_integer: tier3 site ID is integer -> siteID ID sent to AS in integer', - 'param' : { 'tier3SiteID': 12345 }, - 'expected' : 'pass', - }, - { - 'testname' : 'test_prebid_indexAdapter_tier3siteid_quoted_integer: tier3 site ID is quoted integer -> siteID ID sent to AS in integer', - 'param' : { 'tier3SiteID': '12345' }, - 'expected' : 'pass', - }, - { - 'testname' : 'test_prebid_indexAdapter_tier3siteid_float: tier3 site ID is float -> slot is ignored', - 'param' : { 'tier3SiteID': 12.345 }, - 'expected' : 'fail', - }, - { - 'testname' : 'test_prebid_indexAdapter_tier3siteid_string: tier3 site ID is string -> slot is ignored', - 'param' : { 'tier3SiteID': 'string' }, - 'expected' : 'fail', - }, - { - 'testname' : 'test_prebid_indexAdapter_tier3siteid_array: tier3 site ID is array -> slot is ignored', - 'param' : { 'tier3SiteID': [ 12345 ] }, - 'expected' : 'pass', - }, - { - 'testname' : 'test_prebid_indexAdapter_tier3siteid_hash: tier3 site ID is hash -> slot is ignored', - 'param' : { 'tier3SiteID': { 12345: 678 } }, - 'expected' : 'fail', - }, - { - 'testname' : 'test_prebid_indexAdapter_tier3siteid_zero: tier3 site ID is zero integer -> slot is ignored', - 'param' : { 'tier3SiteID': 0 }, - 'expected' : 'fail', - }, - { - 'testname' : 'test_prebid_indexAdapter_tier3siteid_negative: tier3 site ID is a negative integer -> slot is ignored', - 'param' : { 'tier3SiteID': -1234 }, - 'expected' : 'fail', - }, - { - 'testname' : 'test_prebid_indexAdapter_tier3siteid_missing: tier3 site ID is missing -> slot is ignored', - 'param' : { 'missingtier3SiteID': true }, - 'expected' : 'fail', - }, - ]; - function base_prebid_indexAdapter_tier3siteid ( testname, param, expected ) { - it( testname, function(){ - var configuredBids = [ - IndexUtils.createBidSlot( IndexUtils.DefaultPlacementCodePrefix, 'slot_1', [ IndexUtils.supportedSizes[0] ], param ), - ]; - adapter.callBids({ bids: configuredBids }); - - assert.isTrue(adLoader.loadScript.called, "loadScript get request"); - assert.include(adLoader.loadScript.firstCall.args[0], HeaderTagRequest, "request is headertag request"); - - var requestJSON = IndexUtils.parseIndexRequest(adLoader.loadScript.firstCall.args[0]); - assert.isNotNull( requestJSON.r.imp, "headertag request include impression object" ); - - var impressionObj = requestJSON.r.imp; - var expandedBids = configuredBids.map(bid => IndexUtils.expandSizes(bid)) - var sidMatched = IndexUtils.matchBidsOnSID(expandedBids, impressionObj); - - if ( expected == 'pass' ) { - assert.equal( sidMatched.matched.length, 2, 'Two slots are configured and sent to AS'); - - // check normal site id - var normalSitePair = sidMatched.matched[0]; - - var expectedSlotID = normalSitePair.configured.params.id + '_1'; - assert.equal( normalSitePair.sent.ext.sid, expectedSlotID, "request " + normalSitePair.name + " site ID is set to " + expectedSlotID); - assert.isString( normalSitePair.sent.ext.sid, "type of slot ID is string"); - - var expectedSiteID = normalSitePair.configured.params.siteID; - assert.equal(normalSitePair.sent.ext.siteID, expectedSiteID, "request " + normalSitePair.name + " site ID is set to " + expectedSiteID); - assert.isNumber(normalSitePair.sent.ext.siteID, "site ID is integer"); - - // check tier site id - var tier3SitePair = sidMatched.matched[1]; - var expectedTierSlotID = 'T2_' + tier3SitePair.configured.params.id + '_1'; - assert.equal( tier3SitePair.sent.ext.sid, expectedTierSlotID, "request " + tier3SitePair.name + " site ID is set to " + expectedTierSlotID); - assert.isString( tier3SitePair.sent.ext.sid, "type of slot ID is string"); - - var expectedTierSiteID = tier3SitePair.configured.params.tier3SiteID; - assert.equal(tier3SitePair.sent.ext.siteID, expectedTierSiteID, "request " + normalSitePair.name + " site ID is set to " + expectedTierSiteID); - assert.isNumber(tier3SitePair.sent.ext.siteID, "site ID is integer"); - - // check unsent bids - assert.equal( sidMatched.unmatched.configured.length, 0, "All configured bids are in impression Obj"); - assert.equal( sidMatched.unmatched.sent.length, 0, "All bids in impression object are from configured bids"); - } else { - assert.equal( sidMatched.matched.length, 1, 'one slot is configured and sent to AS'); - - // check normal site id - var normalSitePair = sidMatched.matched[0]; - - var expectedSlotID = normalSitePair.configured.params.id + '_1'; - assert.equal( normalSitePair.sent.ext.sid, expectedSlotID, "request " + normalSitePair.name + " site ID is set to " + expectedSlotID); - assert.isString( normalSitePair.sent.ext.sid, "type of slot ID is string"); - - var expectedSiteID = normalSitePair.configured.params.siteID; - assert.equal(normalSitePair.sent.ext.siteID, expectedSiteID, "request " + normalSitePair.name + " site ID is set to " + expectedSiteID); - assert.isNumber(normalSitePair.sent.ext.siteID, "site ID is integer"); - - // check unsent bids - if ( param.missingtier3SiteID ){ - assert.equal( sidMatched.unmatched.configured.length, 0, "one configured bid is missing in impression Obj"); - } else { - assert.equal( sidMatched.unmatched.configured.length, 1, "one configured bid is missing in impression Obj"); - } - assert.equal( sidMatched.unmatched.sent.length, 0, "All bids in impression object are from configured bids"); - } - }); - }; - - for ( var i=0; i < test_indexAdapter_tier3siteid.length; i++ ){ - var test = test_indexAdapter_tier3siteid[i]; - base_prebid_indexAdapter_tier3siteid( test.testname, test.param, test.expected ); - } - - - it( 'test_prebid_indexAdapter_siteID_multiple: multiple slots have same siteIDs -> all slots in ad server request with the same site IDs', function(){ - var first_slot = { - slotName: 'slot1', - siteID: 111111, - }; - var second_slot = { - slotName: 'slot2', - siteID: 111111, // same as first slot - }; - - var configuredBids = [ - IndexUtils.createBidSlot( IndexUtils.DefaultPlacementCodePrefix, first_slot['slotName'], [ IndexUtils.supportedSizes[0] ], { siteID: first_slot['siteID'] } ), - IndexUtils.createBidSlot( IndexUtils.DefaultPlacementCodePrefix, second_slot['slotName'], [ IndexUtils.supportedSizes[1] ], { siteID: second_slot['siteID'] }), - ]; - - adapter.callBids({ bids: configuredBids }); - var requestJSON = IndexUtils.parseIndexRequest(adLoader.loadScript.firstCall.args[0]); - assert.isNotNull( requestJSON.r.imp, "headertag request include impression object" ); - - var impressionObj = requestJSON.r.imp; - - var expandedBids = configuredBids.map(bid => IndexUtils.expandSizes(bid)) - var sidMatched = IndexUtils.matchBidsOnSize(expandedBids, impressionObj); - for ( var i = 0; i < sidMatched.matched.length; i++) { - var pair = sidMatched.matched[i]; - - var expectedSiteID = pair.configured.params.siteID; - var actualSiteID = pair.sent.ext.siteID; - assert.equal(actualSiteID, expectedSiteID, "request " + pair.name + " site ID is set to " + expectedSiteID); - assert.isNumber( actualSiteID, "site ID is number"); - } - - assert.equal( sidMatched.unmatched.sent.length, 0, "All bids in impression object are from configured bids"); - assert.equal( sidMatched.unmatched.configured.length, 0, "All configured bids are in impression Obj"); - }); - - it( 'test_prebid_indexAdapter_siteID_different: multiple slots have different siteIDs -> all slots in ad server request with the different site IDs', function(){ - var first_slot = { - slotName: 'slot1', - siteID: 111111, - }; - var second_slot = { - slotName: 'slot2', - siteID: 222222, - }; - - var configuredBids = [ - IndexUtils.createBidSlot( IndexUtils.DefaultPlacementCodePrefix, first_slot['slotName'], [ IndexUtils.supportedSizes[0] ], { siteID: first_slot['siteID'] } ), - IndexUtils.createBidSlot( IndexUtils.DefaultPlacementCodePrefix, second_slot['slotName'], [ IndexUtils.supportedSizes[1] ], { siteID: second_slot['siteID'] }), - ]; - - adapter.callBids({ bids: configuredBids }); - var requestJSON = IndexUtils.parseIndexRequest(adLoader.loadScript.firstCall.args[0]); - assert.isNotNull( requestJSON.r.imp, "headertag request include impression object" ); - - var impressionObj = requestJSON.r.imp; - - var expandedBids = configuredBids.map(bid => IndexUtils.expandSizes(bid)) - var sidMatched = IndexUtils.matchBidsOnSize(expandedBids, impressionObj); - for ( var i = 0; i < sidMatched.matched.length; i++) { - var pair = sidMatched.matched[i]; - - var expectedSiteID = pair.configured.params.siteID; - var actualSiteID = pair.sent.ext.siteID; - assert.equal(actualSiteID, expectedSiteID, "request " + pair.name + " site ID is set to " + expectedSiteID); - assert.isNumber( actualSiteID, "site ID is number"); - } - - assert.equal( sidMatched.unmatched.sent.length, 0, "All bids in impression object are from configured bids"); - assert.equal( sidMatched.unmatched.configured.length, 0, "All configured bids are in impression Obj"); - }); - - it('test_prebid_indexAdapter_size_singleArr: single sized array -> width and height in integer in request', function () { - var configuredBids = [ - IndexUtils.createBidSlot( IndexUtils.DefaultPlacementCodePrefix, "slot_1", IndexUtils.supportedSizes[0] ) - ]; - adapter.callBids({ bids: configuredBids }); - - assert.isTrue(adLoader.loadScript.called, "loadScript get request"); - - assert.include(adLoader.loadScript.firstCall.args[0], HeaderTagRequest, "request is headertag request"); - - var requestJSON = IndexUtils.parseIndexRequest(adLoader.loadScript.firstCall.args[0]); - assert.isNotNull( requestJSON.r.imp, "headertag request include impression object" ); - - var impressionObj = requestJSON.r.imp; - - var expandedBids = configuredBids.map(bid => IndexUtils.expandSizes(bid)) - var sidMatched = IndexUtils.matchBidsOnSID(expandedBids, impressionObj); - for ( var i = 0; i < sidMatched.matched.length; i++) { - var pair = sidMatched.matched[i]; - - assert.equal(pair.sent.banner.w, pair.configured.size[0], "request " + pair.name + " width is set to " + pair.configured.size[0]); - assert.equal(pair.sent.banner.h, pair.configured.size[1], "request " + pair.name + " width is set to " + pair.configured.size[1]); - assert.equal(pair.sent.ext.siteID, pair.configured.params.siteID, "request " + pair.name + " siteID is set to " + pair.configured.params.siteID); - } - - assert.equal( sidMatched.unmatched.configured.length, 0, "All configured bids are in impression Obj"); - assert.equal( sidMatched.unmatched.sent.length, 0, "All bids in impression object are from configured bids"); - - }); - - it('test_prebid_indexAdapter_size_singleDim: missing width/height -> size is ignored, no ad server request for bad size', function () { - var oneDimSize = [728]; - var configuredBids = [ - IndexUtils.createBidSlot( IndexUtils.DefaultPlacementCodePrefix, "slot_1", [ IndexUtils.supportedSizes[0], oneDimSize, IndexUtils.supportedSizes[1] ] ) - ]; - adapter.callBids({ bids: configuredBids }); - - assert.isTrue(adLoader.loadScript.called, "loadScript get request"); - assert.include(adLoader.loadScript.firstCall.args[0], HeaderTagRequest, "request is headertag request"); - - var requestJSON = IndexUtils.parseIndexRequest(adLoader.loadScript.firstCall.args[0]); - assert.isNotNull( requestJSON.r.imp, "headertag request include impression object" ); - - var impressionObj = requestJSON.r.imp; - - var expandedBids = configuredBids.map(bid => IndexUtils.expandSizes(bid)) - var sidMatched = IndexUtils.matchBidsOnSize(expandedBids, impressionObj); - - for ( var i = 0; i < sidMatched.matched.length; i++) { - var pair = sidMatched.matched[i]; - - assert.equal(pair.sent.banner.w, pair.configured.size[0], "request " + pair.name + " width is set to " + pair.configured.size[0]); - assert.equal(pair.sent.banner.h, pair.configured.size[1], "request " + pair.name + " width is set to " + pair.configured.size[1]); - assert.equal(pair.sent.ext.siteID, pair.configured.params.siteID, "request " + pair.name + " siteID is set to " + pair.configured.params.siteID); - } - - assert.equal( sidMatched.unmatched.sent.length, 0, "All bids in impression object are from configured bids"); - assert.equal( sidMatched.unmatched.configured.length, 1, "1 configured bid is not in impression Obj"); - assert.equal( sidMatched.unmatched.configured[0].size, oneDimSize, "configured bid not in impression obj size width is" + JSON.stringify(oneDimSize) ); - }); - - it('test_prebid_indexAdapter_size_missing: missing size -> slot is ignored, no ad server request', function () { - var configuredBids = [ - IndexUtils.createBidSlot( IndexUtils.DefaultPlacementCodePrefix, "slot_1", [] ) - ]; - adapter.callBids({ bids: configuredBids }); - - assert.isUndefined( adLoader.loadScript.firstCall.args[0], "no request made to AS"); - }); - - it('test_prebid_indexAdapter_size_negativeWidth: negative width -> size is ignored, no ad server request for bad size', function () { - var invalidSize = [-728,90]; - var configuredBids = [ - IndexUtils.createBidSlot( IndexUtils.DefaultPlacementCodePrefix, "slot_1", [ IndexUtils.supportedSizes[0], invalidSize, IndexUtils.supportedSizes[1] ] ) - ]; - adapter.callBids({ bids: configuredBids }); - - assert.isTrue(adLoader.loadScript.called, "loadScript get request"); - assert.include(adLoader.loadScript.firstCall.args[0], HeaderTagRequest, "request is headertag request"); - - var requestJSON = IndexUtils.parseIndexRequest(adLoader.loadScript.firstCall.args[0]); - assert.isNotNull( requestJSON.r.imp, "headertag request include impression object" ); - - var impressionObj = requestJSON.r.imp; - - var expandedBids = configuredBids.map(bid => IndexUtils.expandSizes(bid)) - var sidMatched = IndexUtils.matchBidsOnSize(expandedBids, impressionObj); - - for ( var i = 0; i < sidMatched.matched.length; i++) { - var pair = sidMatched.matched[i]; - - assert.equal(pair.sent.banner.w, pair.configured.size[0], "request " + pair.name + " width is set to " + pair.configured.size[0]); - assert.equal(pair.sent.banner.h, pair.configured.size[1], "request " + pair.name + " width is set to " + pair.configured.size[1]); - assert.equal(pair.sent.ext.siteID, pair.configured.params.siteID, "request " + pair.name + " siteID is set to " + pair.configured.params.siteID); - } - - assert.equal( sidMatched.unmatched.sent.length, 0, "All bids in impression object are from configured bids"); - assert.equal( sidMatched.unmatched.configured.length, 1, "1 configured bid is not in impression Obj"); - assert.equal( sidMatched.unmatched.configured[0].size, invalidSize, "configured bid not in impression obj size width is" + JSON.stringify(invalidSize) ); - }); - - it('test_prebid_indexAdapter_size_negativeHeight: negative height -> size is ignored, no ad server request for bad size', function () { - var invalidSize = [728,-90]; - var configuredBids = [ - IndexUtils.createBidSlot( IndexUtils.DefaultPlacementCodePrefix, "slot_1", [ IndexUtils.supportedSizes[0], invalidSize, IndexUtils.supportedSizes[1] ] ) - ]; - adapter.callBids({ bids: configuredBids }); - - assert.isTrue(adLoader.loadScript.called, "loadScript get request"); - assert.include(adLoader.loadScript.firstCall.args[0], HeaderTagRequest, "request is headertag request"); - - var requestJSON = IndexUtils.parseIndexRequest(adLoader.loadScript.firstCall.args[0]); - assert.isNotNull( requestJSON.r.imp, "headertag request include impression object" ); - - var impressionObj = requestJSON.r.imp; - - var expandedBids = configuredBids.map(bid => IndexUtils.expandSizes(bid)) - var sidMatched = IndexUtils.matchBidsOnSize(expandedBids, impressionObj); - - for ( var i = 0; i < sidMatched.matched.length; i++) { - var pair = sidMatched.matched[i]; - - assert.equal(pair.sent.banner.w, pair.configured.size[0], "request " + pair.name + " width is set to " + pair.configured.size[0]); - assert.equal(pair.sent.banner.h, pair.configured.size[1], "request " + pair.name + " width is set to " + pair.configured.size[1]); - assert.equal(pair.sent.ext.siteID, pair.configured.params.siteID, "request " + pair.name + " siteID is set to " + pair.configured.params.siteID); - } - - assert.equal( sidMatched.unmatched.sent.length, 0, "All bids in impression object are from configured bids"); - assert.equal( sidMatched.unmatched.configured.length, 1, "1 configured bid is not in impression Obj"); - assert.equal( sidMatched.unmatched.configured[0].size, invalidSize, "configured bid not in impression obj size width is" + JSON.stringify(invalidSize) ); - }); - - it('test_prebid_indexAdapter_size_quoted: height and width quoted -> invalid size, no ad server request for invalid size', function () { - var otherSize = ['300','250']; - var configuredBids = [ - IndexUtils.createBidSlot( IndexUtils.DefaultPlacementCodePrefix, "slot_1", [ IndexUtils.supportedSizes[0], otherSize, IndexUtils.supportedSizes[1] ] ) - ]; - adapter.callBids({ bids: configuredBids }); - - assert.isTrue(adLoader.loadScript.called, "loadScript get request"); - assert.include(adLoader.loadScript.firstCall.args[0], HeaderTagRequest, "request is headertag request"); - - var requestJSON = IndexUtils.parseIndexRequest(adLoader.loadScript.firstCall.args[0]); - assert.isNotNull( requestJSON.r.imp, "headertag request include impression object" ); - - var impressionObj = requestJSON.r.imp; - - var expandedBids = configuredBids.map(bid => IndexUtils.expandSizes(bid)); - var sidMatched = IndexUtils.matchBidsOnSize(expandedBids, impressionObj); - - for ( var i = 0; i < sidMatched.matched.length; i++) { - var pair = sidMatched.matched[i]; - - assert.equal(pair.sent.banner.w, pair.configured.size[0], "request " + pair.name + " width is set to " + pair.configured.size[0]); - assert.equal(pair.sent.banner.h, pair.configured.size[1], "request " + pair.name + " width is set to " + pair.configured.size[1]); - assert.equal(pair.sent.ext.siteID, pair.configured.params.siteID, "request " + pair.name + " siteID is set to " + pair.configured.params.siteID); - } - - assert.equal( sidMatched.unmatched.sent.length, 0, "All bids in impression object are from configured bids"); - assert.equal( sidMatched.unmatched.configured.length, 0, "0 configured bid is not in impression Obj"); - }); - - it('test_prebid_indexAdapter_size_float: height and width float -> invalid size, no ad server request for invalid size ', function () { - var otherSize = [300.1,250]; - var configuredBids = [ - IndexUtils.createBidSlot( IndexUtils.DefaultPlacementCodePrefix, "slot_1", [ IndexUtils.supportedSizes[0], otherSize, IndexUtils.supportedSizes[1] ] ) - ]; - adapter.callBids({ bids: configuredBids }); - - assert.isTrue(adLoader.loadScript.called, "loadScript get request"); - assert.include(adLoader.loadScript.firstCall.args[0], HeaderTagRequest, "request is headertag request"); - - var requestJSON = IndexUtils.parseIndexRequest(adLoader.loadScript.firstCall.args[0]); - assert.isNotNull( requestJSON.r.imp, "headertag request include impression object" ); - - var impressionObj = requestJSON.r.imp; - - var expandedBids = configuredBids.map(bid => IndexUtils.expandSizes(bid)); - var sidMatched = IndexUtils.matchBidsOnSize(expandedBids, impressionObj); - - for ( var i = 0; i < sidMatched.matched.length; i++) { - var pair = sidMatched.matched[i]; - - assert.equal(pair.sent.banner.w, pair.configured.size[0], "request " + pair.name + " width is set to " + pair.configured.size[0]); - assert.equal(pair.sent.banner.h, pair.configured.size[1], "request " + pair.name + " width is set to " + pair.configured.size[1]); - assert.equal(pair.sent.ext.siteID, pair.configured.params.siteID, "request " + pair.name + " siteID is set to " + pair.configured.params.siteID); - } - - assert.equal( sidMatched.unmatched.sent.length, 0, "All bids in impression object are from configured bids"); - assert.equal( sidMatched.unmatched.configured.length, 1, "1 configured bid is not in impression Obj"); - assert.equal( sidMatched.unmatched.configured[0].size, otherSize, "configured bid not in impression obj size width is" + JSON.stringify(otherSize) ); - }); - - it('test_prebid_indexAdapter_size_string_1_pba23: height and width string -> invalid size, no ad server request for invalid size ', function () { - var otherSize = [String(IndexUtils.supportedSizes[0][0]), String(IndexUtils.supportedSizes[0][1])]; - var configuredBids = [ - IndexUtils.createBidSlot( IndexUtils.DefaultPlacementCodePrefix, "slot_1", [ IndexUtils.supportedSizes[1], otherSize, IndexUtils.supportedSizes[2] ] ) - ]; - adapter.callBids({ bids: configuredBids }); - - assert.isTrue(adLoader.loadScript.called, "loadScript get request"); - assert.include(adLoader.loadScript.firstCall.args[0], HeaderTagRequest, "request is headertag request"); - - var requestJSON = IndexUtils.parseIndexRequest(adLoader.loadScript.firstCall.args[0]); - assert.isNotNull( requestJSON.r.imp, "headertag request include impression object" ); - - var impressionObj = requestJSON.r.imp; - - var expandedBids = configuredBids.map(bid => IndexUtils.expandSizes(bid)); - var sidMatched = IndexUtils.matchBidsOnSize(expandedBids, impressionObj); - - for ( var i = 0; i < sidMatched.matched.length; i++) { - var pair = sidMatched.matched[i]; - - assert.equal(pair.sent.banner.w, pair.configured.size[0], "request " + pair.name + " width is set to " + pair.configured.size[0]); - assert.equal(pair.sent.banner.h, pair.configured.size[1], "request " + pair.name + " width is set to " + pair.configured.size[1]); - assert.equal(pair.sent.ext.siteID, pair.configured.params.siteID, "request " + pair.name + " siteID is set to " + pair.configured.params.siteID); - } - - assert.equal( sidMatched.unmatched.sent.length, 0, "All bids in impression object are from configured bids"); - assert.equal( sidMatched.unmatched.configured.length, 0, "all configured bids are in impression Obj"); - }); - - it('test_prebid_indexAdapter_size_string_2: whole size is string -> invalid size, no ad server request for invalid size ', function () { - var otherSize = "gallery"; - var configuredBids = [ - IndexUtils.createBidSlot( IndexUtils.DefaultPlacementCodePrefix, "slot_1", [ IndexUtils.supportedSizes[0], otherSize, IndexUtils.supportedSizes[1] ] ) - ]; - adapter.callBids({ bids: configuredBids }); - - assert.isTrue(adLoader.loadScript.called, "loadScript get request"); - assert.include(adLoader.loadScript.firstCall.args[0], HeaderTagRequest, "request is headertag request"); - - var requestJSON = IndexUtils.parseIndexRequest(adLoader.loadScript.firstCall.args[0]); - assert.isNotNull( requestJSON.r.imp, "headertag request include impression object" ); - - var impressionObj = requestJSON.r.imp; - - var expandedBids = configuredBids.map(bid => IndexUtils.expandSizes(bid)); - var sidMatched = IndexUtils.matchBidsOnSize(expandedBids, impressionObj); - - for ( var i = 0; i < sidMatched.matched.length; i++) { - var pair = sidMatched.matched[i]; - - assert.equal(pair.sent.banner.w, pair.configured.size[0], "request " + pair.name + " width is set to " + pair.configured.size[0]); - assert.equal(pair.sent.banner.h, pair.configured.size[1], "request " + pair.name + " width is set to " + pair.configured.size[1]); - assert.equal(pair.sent.ext.siteID, pair.configured.params.siteID, "request " + pair.name + " siteID is set to " + pair.configured.params.siteID); - } - - assert.equal( sidMatched.unmatched.sent.length, 0, "All bids in impression object are from configured bids"); - assert.equal( sidMatched.unmatched.configured.length, 1, "1 configured bid is not in impression Obj"); - assert.equal( sidMatched.unmatched.configured[0].size, otherSize, "configured bid not in impression obj size width is" + JSON.stringify(otherSize) ); - }); - - it('test_prebid_indexAdapter_size_string_3: entire size structure is string -> no ad server request since size is invalid', function () { - var configuredBids = [ - IndexUtils.createBidSlot( IndexUtils.DefaultPlacementCodePrefix, "slot_1", "gallery" ) - ]; - adapter.callBids({ bids: configuredBids }); - - assert.isUndefined( adLoader.loadScript.firstCall.args[0], "no request made to AS"); - }); - - it('test_prebid_indexAdapter_size_hash_1: height or width hash -> invalid size, no ad server request for invalid size ', function () { - var otherSize = [{728:1},90]; - var configuredBids = [ - IndexUtils.createBidSlot( IndexUtils.DefaultPlacementCodePrefix, "slot_1", [ IndexUtils.supportedSizes[0], otherSize, IndexUtils.supportedSizes[1] ] ) - ]; - adapter.callBids({ bids: configuredBids }); - - assert.isTrue(adLoader.loadScript.called, "loadScript get request"); - assert.include(adLoader.loadScript.firstCall.args[0], HeaderTagRequest, "request is headertag request"); - - var requestJSON = IndexUtils.parseIndexRequest(adLoader.loadScript.firstCall.args[0]); - assert.isNotNull( requestJSON.r.imp, "headertag request include impression object" ); - - var impressionObj = requestJSON.r.imp; - - var expandedBids = configuredBids.map(bid => IndexUtils.expandSizes(bid)); - var sidMatched = IndexUtils.matchBidsOnSize(expandedBids, impressionObj); - - for ( var i = 0; i < sidMatched.matched.length; i++) { - var pair = sidMatched.matched[i]; - - assert.equal(pair.sent.banner.w, pair.configured.size[0], "request " + pair.name + " width is set to " + pair.configured.size[0]); - assert.equal(pair.sent.banner.h, pair.configured.size[1], "request " + pair.name + " width is set to " + pair.configured.size[1]); - assert.equal(pair.sent.ext.siteID, pair.configured.params.siteID, "request " + pair.name + " siteID is set to " + pair.configured.params.siteID); - } - - assert.equal( sidMatched.unmatched.sent.length, 0, "All bids in impression object are from configured bids"); - assert.equal( sidMatched.unmatched.configured.length, 1, "1 configured bid is not in impression Obj"); - assert.equal( sidMatched.unmatched.configured[0].size, otherSize, "configured bid not in impression obj size width is" + JSON.stringify(otherSize) ); - }); - - it('test_prebid_indexAdapter_size_hash_2: whole size hash -> invalid size, no ad server request for invalid size ', function () { - var otherSize = {728:1,90:1}; - var configuredBids = [ - IndexUtils.createBidSlot( IndexUtils.DefaultPlacementCodePrefix, "slot_1", [ IndexUtils.supportedSizes[0], otherSize, IndexUtils.supportedSizes[1] ] ) - ]; - adapter.callBids({ bids: configuredBids }); - - assert.isTrue(adLoader.loadScript.called, "loadScript get request"); - assert.include(adLoader.loadScript.firstCall.args[0], HeaderTagRequest, "request is headertag request"); - - var requestJSON = IndexUtils.parseIndexRequest(adLoader.loadScript.firstCall.args[0]); - assert.isNotNull( requestJSON.r.imp, "headertag request include impression object" ); - - var impressionObj = requestJSON.r.imp; - - var expandedBids = configuredBids.map(bid => IndexUtils.expandSizes(bid)); - var sidMatched = IndexUtils.matchBidsOnSize(expandedBids, impressionObj); - - for ( var i = 0; i < sidMatched.matched.length; i++) { - var pair = sidMatched.matched[i]; - - assert.equal(pair.sent.banner.w, pair.configured.size[0], "request " + pair.name + " width is set to " + pair.configured.size[0]); - assert.equal(pair.sent.banner.h, pair.configured.size[1], "request " + pair.name + " width is set to " + pair.configured.size[1]); - assert.equal(pair.sent.ext.siteID, pair.configured.params.siteID, "request " + pair.name + " siteID is set to " + pair.configured.params.siteID); - } - - assert.equal( sidMatched.unmatched.sent.length, 0, "All bids in impression object are from configured bids"); - assert.equal( sidMatched.unmatched.configured.length, 1, "1 configured bid is not in impression Obj"); - assert.equal( sidMatched.unmatched.configured[0].size, otherSize, "configured bid not in impression obj size width is" + JSON.stringify(otherSize) ); - }); - - it('test_prebid_indexAdapter_size_hash_3: entire size structure is hash -> no ad server request since size is invalid', function () { - var configuredBids = [ - IndexUtils.createBidSlot( IndexUtils.DefaultPlacementCodePrefix, "slot_1", {728:90} ) - ]; - adapter.callBids({ bids: configuredBids }); - - assert.isUndefined( adLoader.loadScript.firstCall.args[0], "no request made to AS"); - }); - - it('test_prebid_indexAdapter_size_swap: swap size and width for valid so now its invalid -> unsupportedsize, no ad server request for unsupported size ', function () { - var otherSize = [90,728]; - var configuredBids = [ - IndexUtils.createBidSlot( IndexUtils.DefaultPlacementCodePrefix, "slot_1", [ IndexUtils.supportedSizes[0], otherSize, IndexUtils.supportedSizes[1] ] ) - ]; - adapter.callBids({ bids: configuredBids }); - - assert.isTrue(adLoader.loadScript.called, "loadScript get request"); - assert.include(adLoader.loadScript.firstCall.args[0], HeaderTagRequest, "request is headertag request"); - - var requestJSON = IndexUtils.parseIndexRequest(adLoader.loadScript.firstCall.args[0]); - assert.isNotNull( requestJSON.r.imp, "headertag request include impression object" ); - - var impressionObj = requestJSON.r.imp; - - var expandedBids = configuredBids.map(bid => IndexUtils.expandSizes(bid)); - var sidMatched = IndexUtils.matchBidsOnSize(expandedBids, impressionObj); - - for ( var i = 0; i < sidMatched.matched.length; i++) { - var pair = sidMatched.matched[i]; - - assert.equal(pair.sent.banner.w, pair.configured.size[0], "request " + pair.name + " width is set to " + pair.configured.size[0]); - assert.equal(pair.sent.banner.h, pair.configured.size[1], "request " + pair.name + " width is set to " + pair.configured.size[1]); - assert.equal(pair.sent.ext.siteID, pair.configured.params.siteID, "request " + pair.name + " siteID is set to " + pair.configured.params.siteID); - } - - assert.equal( sidMatched.unmatched.sent.length, 0, "All bids in impression object are from configured bids"); - assert.equal( sidMatched.unmatched.configured.length, 1, "1 configured bid is not in impression Obj"); - assert.equal( sidMatched.unmatched.configured[0].size, otherSize, "configured bid not in impression obj size width is" + JSON.stringify(otherSize) ); - }); - - it('test_prebid_indexAdapter_size_sameWidth: same width for all sizes in a slot -> ad server request only for supported sizes', function () { - var valid1Size = [300,250]; - var otherSize = [300,999]; - var valid2Size = [300,600]; - - var configuredBids = [ - IndexUtils.createBidSlot( IndexUtils.DefaultPlacementCodePrefix, "slot_1", [ valid1Size, otherSize, valid2Size ] ) - ]; - adapter.callBids({ bids: configuredBids }); - - assert.isTrue(adLoader.loadScript.called, "loadScript get request"); - assert.include(adLoader.loadScript.firstCall.args[0], HeaderTagRequest, "request is headertag request"); - - var requestJSON = IndexUtils.parseIndexRequest(adLoader.loadScript.firstCall.args[0]); - assert.isNotNull( requestJSON.r.imp, "headertag request include impression object" ); - - var impressionObj = requestJSON.r.imp; - - var expandedBids = configuredBids.map(bid => IndexUtils.expandSizes(bid)); - var sidMatched = IndexUtils.matchBidsOnSize(expandedBids, impressionObj); - - for ( var i = 0; i < sidMatched.matched.length; i++) { - var pair = sidMatched.matched[i]; - - assert.equal(pair.sent.banner.w, pair.configured.size[0], "request " + pair.name + " width is set to " + pair.configured.size[0]); - assert.equal(pair.sent.banner.h, pair.configured.size[1], "request " + pair.name + " width is set to " + pair.configured.size[1]); - assert.equal(pair.sent.ext.siteID, pair.configured.params.siteID, "request " + pair.name + " siteID is set to " + pair.configured.params.siteID); - } - - assert.equal( sidMatched.unmatched.sent.length, 0, "All bids in impression object are from configured bids"); - assert.equal( sidMatched.unmatched.configured.length, 1, "1 configured bid is not in impression Obj"); - assert.equal( sidMatched.unmatched.configured[0].size, otherSize, "configured bid not in impression obj size width is" + JSON.stringify(otherSize) ); - }); - - it('test_prebid_indexAdapter_size_sameHeight: same height for all sizes in a slot -> ad server request only for supported sizes', function () { - var valid1Size = [120,600]; - var otherSize = [999,600]; - var valid2Size = [300,600]; - - var configuredBids = [ - IndexUtils.createBidSlot( IndexUtils.DefaultPlacementCodePrefix, "slot_1", [ valid1Size, otherSize, valid2Size ] ) - ]; - adapter.callBids({ bids: configuredBids }); - - assert.isTrue(adLoader.loadScript.called, "loadScript get request"); - assert.include(adLoader.loadScript.firstCall.args[0], HeaderTagRequest, "request is headertag request"); - - var requestJSON = IndexUtils.parseIndexRequest(adLoader.loadScript.firstCall.args[0]); - assert.isNotNull( requestJSON.r.imp, "headertag request include impression object" ); - - var impressionObj = requestJSON.r.imp; - - var expandedBids = configuredBids.map(bid => IndexUtils.expandSizes(bid)); - var sidMatched = IndexUtils.matchBidsOnSize(expandedBids, impressionObj); - - for ( var i = 0; i < sidMatched.matched.length; i++) { - var pair = sidMatched.matched[i]; - - assert.equal(pair.sent.banner.w, pair.configured.size[0], "request " + pair.name + " width is set to " + pair.configured.size[0]); - assert.equal(pair.sent.banner.h, pair.configured.size[1], "request " + pair.name + " width is set to " + pair.configured.size[1]); - assert.equal(pair.sent.ext.siteID, pair.configured.params.siteID, "request " + pair.name + " siteID is set to " + pair.configured.params.siteID); - } - - assert.equal( sidMatched.unmatched.sent.length, 0, "All bids in impression object are from configured bids"); - assert.equal( sidMatched.unmatched.configured.length, 1, "1 configured bid is not in impression Obj"); - assert.equal( sidMatched.unmatched.configured[0].size, otherSize, "configured bid not in impression obj size width is" + JSON.stringify(otherSize) ); - }); - - it('test_prebid_indexAdapter_request_sizeID_validation_1: multiple prebid size slot, index slots with size for all prebid slots, 1 slot is not configured properly -> all size in AS request, except misconfigured slot', function () { - var slotID_1 = 52; - var slotID_2 = 53; - var slotSizes_1 = IndexUtils.supportedSizes[0]; - var slotSizes_2 = IndexUtils.supportedSizes[1]; - - var configuredBids = [ - IndexUtils.createBidSlot( IndexUtils.DefaultPlacementCodePrefix, slotID_1, [ slotSizes_1, slotSizes_2 ], { slotSize : [ 728, 'invalid' ] } ), - IndexUtils.createBidSlot( IndexUtils.DefaultPlacementCodePrefix, slotID_2, [ slotSizes_1, slotSizes_2 ], { slotSize : slotSizes_2 } ) - ]; - - adapter.callBids({ bids: configuredBids }); - - assert.isTrue(adLoader.loadScript.called, "loadScript get request"); - - assert.include(adLoader.loadScript.firstCall.args[0], HeaderTagRequest, "request is headertag request"); - - var requestJSON = IndexUtils.parseIndexRequest(adLoader.loadScript.firstCall.args[0]); - assert.isNotNull( requestJSON.r.imp, "headertag request include impression object" ); - - var impressionObj = requestJSON.r.imp; - assert.equal(impressionObj.length, 1, "1 slot is made in the request" ); - - assert.equal(impressionObj[0].banner.w, slotSizes_2[0], "the width made in the request matches with request: " + slotSizes_2[0] ); - assert.equal(impressionObj[0].banner.h, slotSizes_2[1], "the height made in the request matches with request: " + slotSizes_2[1] ); - assert.equal(impressionObj[0].ext.sid, slotID_2, "slotID in the request matches with configuration: " + slotID_2 ); - assert.equal(impressionObj[0].ext.siteID, IndexUtils.DefaultSiteID, "siteID in the request matches with request: " + IndexUtils.DefaultSiteID ); - }); - -}); diff --git a/test/spec/adapters/innity_spec.js b/test/spec/adapters/innity_spec.js deleted file mode 100644 index 850cdf99041..00000000000 --- a/test/spec/adapters/innity_spec.js +++ /dev/null @@ -1,162 +0,0 @@ -describe('innity adapter tests', function () { - - var expect = require('chai').expect; - var urlParse = require('url-parse'); - var querystringify = require('querystringify'); - var adapter = require('src/adapters/innity'); - var adLoader = require('src/adloader'); - var bidmanager = require('src/bidmanager'); - - var stubLoadScript; - - beforeEach(function () { - stubLoadScript = sinon.stub(adLoader, 'loadScript'); - }); - - afterEach(function () { - stubLoadScript.restore(); - }); - - describe('creation of bid url', function () { - - if (typeof($$PREBID_GLOBAL$$._bidsReceived) === "undefined") { - $$PREBID_GLOBAL$$._bidsReceived = []; - } - if (typeof($$PREBID_GLOBAL$$._bidsRequested) === "undefined") { - $$PREBID_GLOBAL$$._bidsRequested = []; - } - - it('bid request for single placement', function () { - - var params = { - bids: [{ - placementCode: '/19968336/header-bid-tag-0', - sizes: [[300,250]], - bidId: 'b12345', - bidder: 'innity', - params: { pub: '267', zone: '62546' } - }] - }; - - adapter().callBids(params); - - var bidUrl = stubLoadScript.getCall(0).args[0]; - - sinon.assert.calledOnce(stubLoadScript); - - var parsedBidUrl = urlParse(bidUrl); - var parsedBidUrlQueryString = querystringify.parse(parsedBidUrl.query); - - expect(parsedBidUrlQueryString).to.have.property('pub').and.to.equal('267'); - expect(parsedBidUrlQueryString).to.have.property('zone').and.to.equal('62546'); - expect(parsedBidUrlQueryString).to.have.property('width').and.to.equal('300'); - expect(parsedBidUrlQueryString).to.have.property('height').and.to.equal('250'); - }); - }); - - describe('handling bid response', function () { - it('should return complete bid response', function() { - - var stubAddBidResponse = sinon.stub(bidmanager, 'addBidResponse'); - - var params = { - bids: [{ - placementCode: '/19968336/header-bid-tag-0', - sizes: [[300,250]], - bidId: 'b12345', - bidder: 'innity', - params: { pub: '267', zone: '62546' } - }] - }; - - var response = { - cpm: 100, - width: 300, - height: 250, - callback_uid: 'b12345', - tag: '', - width: 300, - height: 600 - } - } - }); - }); - - mantis.callBids(callBidExample); - - sinon.assert.calledTwice(bidmanager.addBidResponse); - - expect(bidmanager.addBidResponse.firstCall.args[0]).to.eql('foo'); - - var bid1 = bidmanager.addBidResponse.firstCall.args[1]; - expect(bid1.getStatusCode()).to.eql(constants.STATUS.GOOD); - expect(bid1.bidderCode).to.eql('mantis'); - expect(bid1.cpm).to.eql(1); - expect(bid1.ad).to.eql(''); - expect(bid1.width).to.eql(300); - expect(bid1.height).to.eql(600); - - expect(bidmanager.addBidResponse.secondCall.args[0]).to.eql('bar'); - - var bid2 = bidmanager.addBidResponse.secondCall.args[1]; - expect(bid2.getStatusCode()).to.eql(constants.STATUS.NO_BID); - expect(bid2.bidderCode).to.eql('mantis'); - }); - - it('should load script with relevant bid data', () => { - sandbox.stub(adloader, 'loadScript'); - - mantis.callBids(callBidExample); - - sinon.assert.calledOnce(adloader.loadScript); - - var serverCall = adloader.loadScript.firstCall.args[0]; - - expect(serverCall).to.match(/buster=[0-9]+&/); - expect(serverCall).to.match(/tz=-?[0-9]+&/); - expect(serverCall).to.match(/secure=(true|false)&/); - expect(serverCall).to.string('property=1234&'); - expect(serverCall).to.string('bids[0][bidId]=bidId1&'); - expect(serverCall).to.string('bids[0][sizes][0][width]=728&'); - expect(serverCall).to.string('bids[0][sizes][0][height]=90&'); - expect(serverCall).to.string('bids[0][config][zoneId]=zone1&'); - expect(serverCall).to.string('bids[1][bidId]=bidId2&'); - expect(serverCall).to.string('bids[1][sizes][0][width]=300&'); - expect(serverCall).to.string('bids[1][sizes][0][height]=600&'); - expect(serverCall).to.string('bids[1][sizes][1][width]=300&'); - expect(serverCall).to.string('bids[1][sizes][1][height]=250&'); - expect(serverCall).to.string('bids[1][config][zoneId]=zone2&'); - expect(serverCall).to.string('version=1'); - }); - - /* tests below are to just adhere to code coverage requirements, but it is already tested in our own libraries/deployment process */ - it('should send uuid from window if set', () => { - sandbox.stub(adloader, 'loadScript'); - - window.mantis_uuid = '4321'; - - mantis.callBids(callBidExample); - - sinon.assert.calledOnce(adloader.loadScript); - - var serverCall = adloader.loadScript.firstCall.args[0]; - - expect(serverCall).to.string('uuid=4321&'); - }); - - it('should send mobile = true if breakpoint is hit', () => { - sandbox.stub(adloader, 'loadScript'); - - window.mantis_link = true; // causes iframe detection to not work - window.mantis_breakpoint = 100000000; // force everything to be mobile - - mantis.callBids(callBidExample); - - sinon.assert.calledOnce(adloader.loadScript); - - var serverCall = adloader.loadScript.firstCall.args[0]; - - expect(serverCall).to.string('mobile=true&'); - }); - - it('should send different params if amp is detected', () => { - sandbox.stub(adloader, 'loadScript'); - - window.context = { - tagName: "AMP-AD", - location: { - href: 'bar', - referrer: 'baz' - } - }; - - mantis.callBids(callBidExample); - - sinon.assert.calledOnce(adloader.loadScript); - - var serverCall = adloader.loadScript.firstCall.args[0]; - - expect(serverCall).to.string('mobile=true&'); - // expect(serverCall).to.string('url=bar&'); - }); - }); -}); - diff --git a/test/spec/adapters/piximedia_spec.js b/test/spec/adapters/piximedia_spec.js deleted file mode 100644 index e5e8b3f17f9..00000000000 --- a/test/spec/adapters/piximedia_spec.js +++ /dev/null @@ -1,418 +0,0 @@ -describe('Piximedia adapter tests', function () { - - var expect = require('chai').expect; - var urlParse = require('url-parse'); - - //var querystringify = require('querystringify'); - - var adapter = require('src/adapters/piximedia'); - var adLoader = require('src/adloader'); - var bidmanager = require('src/bidmanager'); - var utils = require('src/utils'); - var CONSTANTS = require('src/constants.json'); - - var pbjs = window.pbjs = window.pbjs || {}; - let stubLoadScript; - - beforeEach(function () { - stubLoadScript = sinon.stub(adLoader, 'loadScript'); - }); - - afterEach(function () { - stubLoadScript.restore(); - }); - - describe('creation of prebid url', function () { - if (typeof(pbjs._bidsReceived)==="undefined"){ - pbjs._bidsReceived = []; - } - if (typeof(pbjs._bidsRequested)==="undefined"){ - pbjs._bidsRequested = []; - } - if (typeof(pbjs._adsReceived)==="undefined"){ - pbjs._adsReceived = []; - } - - it('should call the Piximedia prebid URL once on valid calls', function () { - var params = { - bidderCode: 'piximedia', - bidder: 'piximedia', - bids: [ - { - bidId: '4d3819cffc4d12', - sizes: [[300, 250]], - bidder: 'piximedia', - params: { siteId: 'TEST', placementId: "TEST", prebidUrl: "//resources.pm/tests/prebid/bids.js" }, - requestId: '59c318fd382219', - placementCode: '/20164912/header-bid-tag-0' - } - ] - }; - - adapter().callBids(params); - sinon.assert.calledOnce(stubLoadScript); - }); - - it('should not call the Piximedia prebid URL once on invalid calls', function () { - var params = { - bidderCode: 'piximedia', - bidder: 'piximedia', - bids: [ - { - bidId: '4d3819cffc4d12', - sizes: [[300, 250]], - bidder: 'piximedia', - params: { prebidUrl: "//resources.pm/tests/prebid/bids.js" }, // this is invalid: site and placement ID are missing - requestId: '59c318fd382219', - placementCode: '/20164912/header-bid-tag-0' - } - ] - }; - - adapter().callBids(params); - sinon.assert.notCalled(stubLoadScript); - }); - - it('should call the correct Prebid URL when using the default URL', function () { - var params = { - bidderCode: 'piximedia', - bidder: 'piximedia', - bids: [ - { - bidId: '4d3819cffc4d12', - sizes: [[300, 250]], - bidder: 'piximedia', - params: { siteId: 'TEST', placementId: "TEST" }, - requestId: '59c318fd382219', - placementCode: '/20164912/header-bid-tag-0' - } - ] - }; - - adapter().callBids(params); - var bidUrl = stubLoadScript.getCall(0).args[0]; - - sinon.assert.calledWith(stubLoadScript, bidUrl); - - var parsedBidUrl = urlParse(bidUrl); - - expect(parsedBidUrl.hostname).to.equal("static.adserver.pm"); - expect(parsedBidUrl.query).to.equal(""); - expect(parsedBidUrl.pathname.replace(/cbid=[a-f0-9]+/, "cbid=210af5668b1e23").replace(/rand=[0-9]+$/, "rand=42")).to.equal("/prebid/site_id=TEST/placement_id=TEST/jsonp=pbjs.handlePiximediaCallback/sizes=300x250/cbid=210af5668b1e23/rand=42"); - }); - - it('should call the correct Prebid URL when using the default URL with a deal and custom data', function () { - var params = { - bidderCode: 'piximedia', - bidder: 'piximedia', - bids: [ - { - bidId: '4d3819cffc4d12', - sizes: [[300, 250]], - bidder: 'piximedia', - params: { siteId: 'TEST', placementId: "TEST", dealId: 1295, custom: "bespoke", custom2: function() { return "bespoke2"; }, custom3: null, custom4: function() {} }, - requestId: '59c318fd382219', - placementCode: '/20164912/header-bid-tag-0' - } - ] - }; - - adapter().callBids(params); - var bidUrl = stubLoadScript.getCall(0).args[0]; - - sinon.assert.calledWith(stubLoadScript, bidUrl); - - var parsedBidUrl = urlParse(bidUrl); - - expect(parsedBidUrl.hostname).to.equal("static.adserver.pm"); - expect(parsedBidUrl.query).to.equal(""); - expect(parsedBidUrl.pathname.replace(/cbid=[a-f0-9]+/, "cbid=210af5668b1e23").replace(/rand=[0-9]+$/, "rand=42")).to.equal("/prebid/site_id=TEST/placement_id=TEST/l_id=1295/custom=bespoke/custom2=bespoke2/custom3=/custom4=/jsonp=pbjs.handlePiximediaCallback/sizes=300x250/cbid=210af5668b1e23/rand=42"); - }); - - it('should call the correct Prebid URL when using the default URL and overridding sizes', function () { - var params = { - bidderCode: 'piximedia', - bidder: 'piximedia', - bids: [ - { - bidId: '4d3819cffc4d12', - sizes: [[300, 250]], - bidder: 'piximedia', - params: { siteId: 'TEST', placementId: "TEST", sizes: [[300,600],[728,90]] }, - requestId: '59c318fd382219', - placementCode: '/20164912/header-bid-tag-0' - } - ] - }; - - adapter().callBids(params); - var bidUrl = stubLoadScript.getCall(0).args[0]; - - sinon.assert.calledWith(stubLoadScript, bidUrl); - - var parsedBidUrl = urlParse(bidUrl); - - expect(parsedBidUrl.hostname).to.equal("static.adserver.pm"); - expect(parsedBidUrl.query).to.equal(""); - expect(parsedBidUrl.pathname.replace(/cbid=[a-f0-9]+/, "cbid=210af5668b1e23").replace(/rand=[0-9]+$/, "rand=42")).to.equal("/prebid/site_id=TEST/placement_id=TEST/jsonp=pbjs.handlePiximediaCallback/sizes=300x600%2C728x90/cbid=210af5668b1e23/rand=42"); - }); - - it('should call the correct Prebid URL when supplying a custom URL', function () { - var params = { - bidderCode: 'piximedia', - bidder: 'piximedia', - bids: [ - { - bidId: '4d3819cffc4d12', - sizes: [[300, 250]], - bidder: 'piximedia', - params: { siteId: 'TEST', placementId: "TEST", prebidUrl: "//resources.pm/tests/prebid/bids.js" }, - requestId: '59c318fd382219', - placementCode: '/20164912/header-bid-tag-0' - } - ] - }; - - adapter().callBids(params); - var bidUrl = stubLoadScript.getCall(0).args[0]; - - sinon.assert.calledWith(stubLoadScript, bidUrl); - - var parsedBidUrl = urlParse(bidUrl); - - expect(parsedBidUrl.hostname).to.equal("resources.pm"); - expect(parsedBidUrl.query).to.equal(""); - expect(parsedBidUrl.pathname.replace(/cbid=[a-f0-9]+/, "cbid=210af5668b1e23").replace(/rand=[0-9]+$/, "rand=42")).to.equal("/tests/prebid/bids.js/site_id=TEST/placement_id=TEST/jsonp=pbjs.handlePiximediaCallback/sizes=300x250/cbid=210af5668b1e23/rand=42"); - }); - }); - - describe('handling of the callback response', function () { - if (typeof(pbjs._bidsReceived)==="undefined"){ - pbjs._bidsReceived = []; - } - if (typeof(pbjs._bidsRequested)==="undefined"){ - pbjs._bidsRequested = []; - } - if (typeof(pbjs._adsReceived)==="undefined"){ - pbjs._adsReceived = []; - } - - var params = { - bidderCode: 'piximedia', - bidder: 'piximedia', - bids: [ - { - bidId: '4d3819cffc4d12', - sizes: [[300, 250]], - bidder: 'piximedia', - params: { siteId: 'TEST', placementId: "TEST", prebidUrl: "//resources.pm/tests/prebid/bids.js" }, - requestId: '59c318fd382219', - placementCode: '/20164912/header-bid-tag-0' - } - ] - }; - - it('Piximedia callback function should exist', function () { - expect(pbjs.handlePiximediaCallback).to.exist.and.to.be.a('function'); - }); - - it('bidmanager.addBidResponse should be called once with correct arguments', function () { - var stubAddBidResponse = sinon.stub(bidmanager, 'addBidResponse'); - var stubGetUniqueIdentifierStr = sinon.spy(utils, "getUniqueIdentifierStr"); - - var response = { - foundbypm: true, - currency: "EUR", - cpm: 1.23, - dealId: 9948, - width: 300, - height: 250, - html: "
ad
" - }; - - adapter().callBids(params); - - var adUnits = []; - var unit = {}; - unit.bids = [params]; - unit.code = '/20164912/header-bid-tag'; - unit.sizes=[[300,250],[728,90]]; - adUnits.push(unit); - - if (typeof(pbjs._bidsRequested)==="undefined"){ - pbjs._bidsRequested = [params]; - } else { - pbjs._bidsRequested.push(params); - } - pbjs.adUnits = adUnits; - response.cbid = stubGetUniqueIdentifierStr.returnValues[0]; - - pbjs.handlePiximediaCallback(response); - - sinon.assert.calledOnce(stubAddBidResponse); - var bidPlacementCode1 = stubAddBidResponse.getCall(0).args[0]; - var bidObject1 = stubAddBidResponse.getCall(0).args[1]; - - expect(bidPlacementCode1).to.equal('/20164912/header-bid-tag-0'); - expect(bidObject1.cpm).to.equal(1.23); - expect(bidObject1.ad).to.equal("
ad
"); - expect(bidObject1.width).to.equal(300); - expect(bidObject1.dealId).to.equal(9948); - expect(bidObject1.height).to.equal(250); - expect(bidObject1.getStatusCode()).to.equal(CONSTANTS.STATUS.GOOD); - expect(bidObject1.bidderCode).to.equal('piximedia'); - - stubAddBidResponse.restore(); - stubGetUniqueIdentifierStr.restore(); - }); - - it('bidmanager.addBidResponse should be called once with correct arguments on partial response', function () { - var stubAddBidResponse = sinon.stub(bidmanager, 'addBidResponse'); - var stubGetUniqueIdentifierStr = sinon.spy(utils, "getUniqueIdentifierStr"); - - // this time, we do not provide dealId - var response = { - foundbypm: true, - cpm: 1.23, - width: 300, - height: 250, - currency: "EUR", - html: "
ad
" - }; - - adapter().callBids(params); - - var adUnits = []; - var unit = {}; - unit.bids = [params]; - unit.code = '/20164912/header-bid-tag'; - unit.sizes=[[300,250],[728,90]]; - adUnits.push(unit); - - if (typeof(pbjs._bidsRequested)==="undefined"){ - pbjs._bidsRequested = [params]; - } else { - pbjs._bidsRequested.push(params); - } - pbjs.adUnits = adUnits; - response.cbid = stubGetUniqueIdentifierStr.returnValues[0]; - - pbjs.handlePiximediaCallback(response); - - sinon.assert.calledOnce(stubAddBidResponse); - var bidPlacementCode1 = stubAddBidResponse.getCall(0).args[0]; - var bidObject1 = stubAddBidResponse.getCall(0).args[1]; - - expect(bidPlacementCode1).to.equal('/20164912/header-bid-tag-0'); - expect(bidObject1.cpm).to.equal(1.23); - expect(bidObject1.ad).to.equal("
ad
"); - expect(bidObject1.width).to.equal(300); - expect(bidObject1.height).to.equal(250); - expect(bidObject1.getStatusCode()).to.equal(CONSTANTS.STATUS.GOOD); - expect(bidObject1.bidderCode).to.equal('piximedia'); - - stubAddBidResponse.restore(); - stubGetUniqueIdentifierStr.restore(); - }); - - it('bidmanager.addBidResponse should be called once without any ads', function () { - var stubAddBidResponse = sinon.stub(bidmanager, 'addBidResponse'); - var stubGetUniqueIdentifierStr = sinon.spy(utils, "getUniqueIdentifierStr"); - - var response = { - foundbypm: false - }; - - adapter().callBids(params); - - var adUnits = []; - var unit = {}; - unit.bids = [params]; - unit.code = '/20164912/header-bid-tag'; - unit.sizes=[[300,250],[728,90]]; - adUnits.push(unit); - - if (typeof(pbjs._bidsRequested)==="undefined"){ - pbjs._bidsRequested = [params]; - } else { - pbjs._bidsRequested.push(params); - } - pbjs.adUnits = adUnits; - response.cbid = stubGetUniqueIdentifierStr.returnValues[0]; - - pbjs.handlePiximediaCallback(response); - - sinon.assert.calledOnce(stubAddBidResponse); - var bidPlacementCode1 = stubAddBidResponse.getCall(0).args[0]; - var bidObject1 = stubAddBidResponse.getCall(0).args[1]; - - expect(bidPlacementCode1).to.equal('/20164912/header-bid-tag-0'); - expect(bidObject1.getStatusCode()).to.equal(CONSTANTS.STATUS.NO_BID); - expect(bidObject1.bidderCode).to.equal('piximedia'); - - stubAddBidResponse.restore(); - stubGetUniqueIdentifierStr.restore(); - }); - - it('bidmanager.addBidResponse should not be called on bogus cbid', function () { - var stubAddBidResponse = sinon.stub(bidmanager, 'addBidResponse'); - var stubGetUniqueIdentifierStr = sinon.spy(utils, "getUniqueIdentifierStr"); - - var response = { - foundbypm: false - }; - - adapter().callBids(params); - - var adUnits = []; - var unit = {}; - unit.bids = [params]; - unit.code = '/20164912/header-bid-tag'; - unit.sizes=[[300,250],[728,90]]; - adUnits.push(unit); - - if (typeof(pbjs._bidsRequested)==="undefined"){ - pbjs._bidsRequested = [params]; - } else { - pbjs._bidsRequested.push(params); - } - pbjs.adUnits = adUnits; - response.cbid = stubGetUniqueIdentifierStr.returnValues[0] + "_BOGUS"; - - pbjs.handlePiximediaCallback(response); - - sinon.assert.notCalled(stubAddBidResponse); - - stubAddBidResponse.restore(); - stubGetUniqueIdentifierStr.restore(); - }); - - it('bidmanager.addBidResponse should not be called on bogus response', function () { - var stubAddBidResponse = sinon.stub(bidmanager, 'addBidResponse'); - - var response = null; // this is bogus: we expect an object - - adapter().callBids(params); - - var adUnits = []; - var unit = {}; - unit.bids = [params]; - unit.code = '/20164912/header-bid-tag'; - unit.sizes=[[300,250],[728,90]]; - adUnits.push(unit); - - if (typeof(pbjs._bidsRequested)==="undefined"){ - pbjs._bidsRequested = [params]; - } else { - pbjs._bidsRequested.push(params); - } - pbjs.adUnits = adUnits; - - pbjs.handlePiximediaCallback(response); - - sinon.assert.notCalled(stubAddBidResponse); - - stubAddBidResponse.restore(); - }); - }); -}); diff --git a/test/spec/adapters/prebidServer_spec.js b/test/spec/adapters/prebidServer_spec.js deleted file mode 100644 index ec62794207c..00000000000 --- a/test/spec/adapters/prebidServer_spec.js +++ /dev/null @@ -1,125 +0,0 @@ -import { expect } from 'chai'; -import Adapter from 'src/adapters/prebidServer'; -import bidmanager from 'src/bidmanager'; -import CONSTANTS from 'src/constants.json'; - -const REQUEST = { - "account_id": "1", - "tid": "437fbbf5-33f5-487a-8e16-a7112903cfe5", - "max_bids": 1, - "timeout_millis": 1000, - "url": "", - "prebid_version": "0.21.0-pre", - "ad_units": [ - { - "code": "div-gpt-ad-1460505748561-0", - "sizes": [ - { - "w": 300, - "h": 250 - }, - { - "w": 300, - "h": 600 - } - ], - "transactionId": "4ef956ad-fd83-406d-bd35-e4bb786ab86c", - "bids": [ - { - "bid_id" : "123", - "bidder": "appnexus", - "params": { - "placementId": "10433394" - } - } - ] - } - ] -}; - -const RESPONSE = { - "tid": "437fbbf5-33f5-487a-8e16-a7112903cfe5", - "status": "OK", - "bidder_status": [ - { - "bidder": "appnexus", - "response_time_ms": 52, - "num_bids": 1 - } - ], - "bids": [ - { - "bid_id": "123", - "code": "div-gpt-ad-1460505748561-0", - "creative_id": "29681110", - "bidder": "appnexus", - "price": 0.5, - "adm": "", - "width": 300, - "height": 250 - } - ] -}; - -describe('S2S Adapter', () => { - - let adapter; - - beforeEach(() => adapter = Adapter.createNew()); - - describe('request function', () => { - - let xhr; - let requests; - - beforeEach(() => { - xhr = sinon.useFakeXMLHttpRequest(); - requests = []; - xhr.onCreate = request => requests.push(request); - }); - - afterEach(() => xhr.restore()); - - it('exists and is a function', () => { - expect(adapter.callBids).to.exist.and.to.be.a('function'); - }); - - }); - - describe('response handler', () => { - - let server; - let config = { - accountId : '1', - enabled : true, - bidders : ['appnexus'], - timeout : 1000, - endpoint : CONSTANTS.S2S.DEFAULT_ENDPOINT - }; - - beforeEach(() => { - server = sinon.fakeServer.create(); - sinon.stub(bidmanager, 'addBidResponse'); - }); - - afterEach(() => { - server.restore(); - bidmanager.addBidResponse.restore(); - }); - - it('registers bids', () => { - server.respondWith(JSON.stringify(RESPONSE)); - - adapter.setConfig(config); - adapter.callBids(REQUEST); - server.respond(); - sinon.assert.calledOnce(bidmanager.addBidResponse); - - const response = bidmanager.addBidResponse.firstCall.args[1]; - expect(response).to.have.property('statusMessage', 'Bid available'); - expect(response).to.have.property('cpm', 0.5); - }); - - }); - -}); diff --git a/test/spec/adapters/pubgears_spec.js b/test/spec/adapters/pubgears_spec.js deleted file mode 100644 index 329d74bb5b3..00000000000 --- a/test/spec/adapters/pubgears_spec.js +++ /dev/null @@ -1,298 +0,0 @@ -import { expect } from 'chai'; -import Adapter from 'src/adapters/pubgears' -import bidmanager from 'src/bidmanager' - -describe('PubGearsAdapter', () => { - - var adapter, mockScript - , params = { - bids: [] - } - - beforeEach( () => { - adapter = new Adapter() - mockScript = document.createElement('script') - sinon.spy(mockScript, 'setAttribute') - } ) - - describe('request function', () => { - - beforeEach( () => { - sinon.spy(document, 'createElement') - }) - - afterEach( () => { - document.createElement.restore && document.createElement.restore() - var s = document.getElementById('pg-header-tag') - if(s) - s.parentNode.removeChild(s) - } ) - - it('has `#callBids()` method', () => { - expect(adapter.callBids).to.exist.and.to.be.a('function') - }) - - it('requires bids to make script', () => { - - adapter.callBids({bids: []}) - expect(document.createElement.notCalled).to.be.ok - }) - - it('creates script when passed bids', () => { - - adapter.callBids({ - bidderCode: "pubgears", - bids: [ - { - bidder: "pubgears", - sizes: [ [300,250] ], - adUnitCode: "foo123/header-bid-tag", - params: { - publisherName: "integration", - pubZone: "testpub.com/combined" - } - } - ] - }) - - sinon.assert.calledWith(document.createElement, 'script') - }) - - it('should assign attributes to script', () => { - - adapter.callBids({ - bidderCode: "pubgears", - bids: [ - { - bidder: "pubgears", - sizes: [ [300,250] ], - adUnitCode: "foo123/header-bid-tag", - params: { - publisherName: "integration", - pubZone: "testpub.com/combined" - } - }, - { - bidder: "pubgears", - sizes: [ [160,600] ], - adUnitCode: "foo123/header-bid-tag", - params: { - publisherName: "integration", - pubZone: "testpub.com/combined" - } - } - ] - }) - var script = document.createElement.returnValues[0] - var slots = script.getAttribute('data-bsm-slot-list') - expect(slots).to.equal('testpub.com/combined@300x250 testpub.com/combined@160x600') - expect(script.getAttribute('data-bsm-flag')).to.equal('true') - expect(script.getAttribute('data-bsm-pub')).to.equal('integration') - expect(script.getAttribute('src')).to.equal('//c.pubgears.com/tags/h') - expect(script.id).to.equal('pg-header-tag') - }) - - it('should reuse existing script when called twice', () => { - - var params = { - bidderCode: "pubgears", - bids: [ - { - bidder: "pubgears", - sizes: [ [300,250] ], - adUnitCode: "foo123/header-bid-tag", - params: { - publisherName: "integration", - pubZone: "testpub.com/combined" - } - }, - { - bidder: "pubgears", - sizes: [ [160,600] ], - adUnitCode: "foo123/header-bid-tag", - params: { - publisherName: "integration", - pubZone: "testpub.com/combined" - } - } - ] - } - adapter.callBids(params) - expect(document.createElement.calledOnce).to.be.true - adapter.callBids(params) - expect(document.createElement.calledOnce).to.be.true - }) - - it('should register event listeners', () => { - - var script = document.createElement('script') - script.id = 'pg-header-tag' - var spy = sinon.spy(script, 'addEventListener') - document.body.appendChild(script) - var params = { - bidderCode: "pubgears", - bids: [ - { - bidder: "pubgears", - sizes: [ [300,250] ], - adUnitCode: "foo123/header-bid-tag", - params: { - publisherName: "integration", - pubZone: "testpub.com/combined" - } - }, - { - bidder: "pubgears", - sizes: [ [160,600] ], - adUnitCode: "foo123/header-bid-tag", - params: { - publisherName: "integration", - pubZone: "testpub.com/combined" - } - } - ] - } - adapter.callBids(params) - - expect(spy.calledWith('onBidResponse')).to.be.ok - expect(spy.calledWith('onResourceComplete')).to.be.ok - }) - }) - - describe('bids received', () => { - - beforeEach(() => { - sinon.spy(bidmanager, 'addBidResponse') - }) - - afterEach(() => { - bidmanager.addBidResponse.restore() - }) - - it('should call bidManager.addBidResponse() when bid received', () => { - - var options = { - bubbles: false, - cancelable: false, - detail: { - gross_price: 1000, - resource: { - position: 'atf', - pub_zone: 'testpub.com/combined', - size: '300x250' - } - } - } - - adapter.callBids({ - bidderCode: "pubgears", - bids: [ - { - bidder: "pubgears", - sizes: [ [300,250] ], - adUnitCode: "foo123/header-bid-tag", - params: { - publisherName: "integration", - pubZone: "testpub.com/combined" - } - }, - { - bidder: "pubgears", - sizes: [ [160,600] ], - adUnitCode: "foo123/header-bid-tag", - params: { - publisherName: "integration", - pubZone: "testpub.com/combined" - } - } - ] - - }) - var script = document.getElementById('pg-header-tag') - var event = new CustomEvent('onBidResponse', options) - script.dispatchEvent(event) - - expect(bidmanager.addBidResponse.calledOnce).to.be.ok - }) - - it('should send correct bid response object when receiving onBidResponse event', () => { - expect(bidmanager.addBidResponse.calledOnce).to.not.be.ok - var bid = { - bidder: "pubgears", - sizes: [ [300,250] ], - adUnitCode: "foo123/header-bid-tag", - params: { - publisherName: "integration", - pubZone: "testpub.com/combined" - } - } - - adapter.callBids({ - bidderCode: "pubgears", - bids: [ bid ] - }) - - var options = { - bubbles: false, - cancelable: false, - detail: { - gross_price: 1000, - resource: { - position: 'atf', - pub_zone: 'testpub.com/combined', - size: '300x250' - } - } - } - var script = document.getElementById('pg-header-tag') - var event = new CustomEvent('onBidResponse', options) - script.dispatchEvent(event) - - var args = bidmanager.addBidResponse.getCall(1).args - expect(args).to.have.length(2) - var bidResponse = args[1] - expect(bidResponse.ad).to.contain(bid.params.pubZone) - }) - - it('should send $0 bid as no-bid response', () => { - - var bid = { - bidder: "pubgears", - sizes: [ [300,250] ], - adUnitCode: "foo123/header-bid-tag", - params: { - publisherName: "integration", - pubZone: "testpub.com/combined" - } - } - - adapter.callBids({ - bidderCode: "pubgears", - bids: [ bid ] - }) - - var options = { - bubbles: false, - cancelable: false, - detail: { - gross_price: 0, - resource: { - position: 'atf', - pub_zone: 'testpub.com/combined', - size: '300x250' - } - } - } - var script = document.getElementById('pg-header-tag') - var event = new CustomEvent('onBidResponse', options) - - bidmanager.addBidResponse.reset() - script.dispatchEvent(event) - - var args = bidmanager.addBidResponse.getCall(1).args - var bidResponse = args[1] - expect(bidResponse).to.be.a('object') - expect(bidResponse.getStatusCode()).to.equal(2) - }) - }) -}) diff --git a/test/spec/adapters/pulsepointLite_spec.js b/test/spec/adapters/pulsepointLite_spec.js deleted file mode 100644 index 811ed583dcb..00000000000 --- a/test/spec/adapters/pulsepointLite_spec.js +++ /dev/null @@ -1,108 +0,0 @@ -import {expect} from 'chai'; -import PulsePointAdapter from 'src/adapters/pulsepointLite'; -import bidManager from 'src/bidmanager'; -import * as ajax from "src/ajax"; -import {parse as parseURL} from 'src/url'; - -describe("PulsePoint Lite Adapter Tests", () => { - - let pulsepointAdapter = new PulsePointAdapter(); - let slotConfigs; - let ajaxStub; - - beforeEach(() => { - sinon.stub(bidManager, 'addBidResponse'); - ajaxStub = sinon.stub(ajax, 'ajax'); - - slotConfigs = { - bids: [ - { - placementCode: "/DfpAccount1/slot1", - bidder: "pulsepoint", - bidId: 'bid12345', - params: { - cp: "p10000", - ct: "t10000", - cf: "300x250" - } - },{ - placementCode: "/DfpAccount2/slot2", - bidder: "pulsepoint", - bidId: 'bid23456', - params: { - cp: "p20000", - ct: "t20000", - cf: "728x90" - } - } - ] - }; - }); - - afterEach(() => { - bidManager.addBidResponse.restore(); - ajaxStub.restore(); - }); - - it('Verify requests sent to PulsePoint', () => { - pulsepointAdapter.callBids(slotConfigs); - var call = parseURL(ajaxStub.firstCall.args[0]).search; - //slot 1 - // expect(call.cp).to.equal('p10000'); - // expect(call.ct).to.equal('t10000'); - // expect(call.cf).to.equal('300x250'); - expect(call.ca).to.equal('BID'); - expect(call.cn).to.equal('1'); - //slot 2 - call = parseURL(ajaxStub.secondCall.args[0]).search; - // expect(call.cp).to.equal('p20000'); - // expect(call.ct).to.equal('t20000'); - // expect(call.cf).to.equal('728x90'); - expect(call.ca).to.equal('BID'); - expect(call.cn).to.equal('1'); - }); - - it('Verify bid', () => { - pulsepointAdapter.callBids(slotConfigs); - //trigger a mock ajax callback with bid. - ajaxStub.firstCall.args[1](JSON.stringify({ - html: 'This is an Ad', - bidCpm: 1.25 - })); - let placement = bidManager.addBidResponse.firstCall.args[0]; - let bid = bidManager.addBidResponse.firstCall.args[1]; - expect(placement).to.equal('/DfpAccount1/slot1'); - expect(bid.bidderCode).to.equal('pulsepoint'); - expect(bid.cpm).to.equal(1.25); - expect(bid.ad).to.equal('This is an Ad'); - expect(bid.width).to.equal('300'); - expect(bid.height).to.equal('250'); - expect(bid.adId).to.equal('bid12345'); - }); - - it('Verify passback', () => { - pulsepointAdapter.callBids(slotConfigs); - //trigger a mock ajax callback with no bid. - ajaxStub.firstCall.args[1](null); - let placement = bidManager.addBidResponse.firstCall.args[0]; - let bid = bidManager.addBidResponse.firstCall.args[1]; - expect(placement).to.equal('/DfpAccount1/slot1'); - expect(bid.bidderCode).to.equal('pulsepoint'); - expect(bid).to.not.have.property('ad'); - expect(bid).to.not.have.property('cpm'); - expect(bid.adId).to.equal('bid12345'); - }); - - it('Verify passback when ajax call fails', () => { - ajaxStub.throws(); - pulsepointAdapter.callBids(slotConfigs); - let placement = bidManager.addBidResponse.firstCall.args[0]; - let bid = bidManager.addBidResponse.firstCall.args[1]; - expect(placement).to.equal('/DfpAccount1/slot1'); - expect(bid.bidderCode).to.equal('pulsepoint'); - expect(bid).to.not.have.property('ad'); - expect(bid).to.not.have.property('cpm'); - expect(bid.adId).to.equal('bid12345'); - }); - -}); diff --git a/test/spec/adapters/rhythmone_spec.js b/test/spec/adapters/rhythmone_spec.js deleted file mode 100644 index 00f19a551d3..00000000000 --- a/test/spec/adapters/rhythmone_spec.js +++ /dev/null @@ -1,91 +0,0 @@ -var r1 = require('../../../src/adapters/rhythmone.js'); -var assert = require('assert'); - -describe('rhythmone adapter tests', function () { - describe('rhythmoneResponse', function () { - - var fakeResponse = { - "id": "1fe94c2e-4b31-4e09-b074-ba90fe7ce92d", - "seatbid": [ - { - "bid": [ - { - "id": "ff8b09b1-5264-52be-4b7b-0156526452bf", - "impid": "div-gpt-ad-1438287399331-0", - "price": 1.0, - "adid": "35858", - "adm": "\"\"", - "adomain": ["www.rhythmone.com"], - "cid": "35857", - "cat": [], - "h": 250, - "w": 300 - } - ], - "seat": "14", - "group": 0 - } - ], - "bidid": "ff8b09b1-5264-52be-4b7b-0156526452bf" - }; - - var endEvent = function(){}, - wonEvent = function(){};; - - var z = new r1( - { - addBidResponse: function(placementcode, adResponse){ - it("should echo placementcode div-gpt-ad-1438287399331-0", function(){ - assert.equal(placementcode, "div-gpt-ad-1438287399331-0"); - }); - it("should have the expected ad response", function(){ - assert.equal((adResponse.ad === undefined || adResponse.ad.length > 0), true); - assert.equal(adResponse.width, 300); - assert.equal(adResponse.height, 250); - assert.equal(adResponse.cpm, 1); - assert.equal(adResponse.bidderCode, "rhythmone"); - }); - } - }, - { - "navigator":{}, - "pbjs":{ - "onEvent":function(e, f){ - if(e.toLowerCase() === "auctionend") endEvent = f; - if(e.toLowerCase() === "bidwon") wonEvent = f; - }, - "getBidResponses":function(){return {"div-gpt-ad-1438287399331-0":{"bids":[{cpm:1,bidderCode:"rhythmone"},{cpm:2,bidderCode:"rhythmone"}]}};}, - "version": "v0.20.0-pre" - } - }, - function(url, callback){ - callback(JSON.stringify(fakeResponse), {status:200, responseText: JSON.stringify(fakeResponse)}); - }); - - z.callBids({ - "bidderCode":"rhythmone", - "bids":[ - { - "bidder":"rhythmone", - "params":{ - "placementId":"xyz", - "keywords":"", - "categories":[], - "trace":true, - "method":"get", - "endpoint":"http://fakedomain.com" - }, - "mediaType": "video", - "placementCode":"div-gpt-ad-1438287399331-0", - "sizes":[[300,250]] - } - ] - }); - - endEvent(); - wonEvent({ - bidderCode: "rhythmone", - adUnitCode: "div-gpt-ad-1438287399331-0" - }); - }); -}); \ No newline at end of file diff --git a/test/spec/adapters/sekindoUM_spec.js b/test/spec/adapters/sekindoUM_spec.js deleted file mode 100644 index ff59b247550..00000000000 --- a/test/spec/adapters/sekindoUM_spec.js +++ /dev/null @@ -1,86 +0,0 @@ -import {expect} from 'chai'; -import sekindoUMAdapter from '../../../src/adapters/sekindoUM'; -var bidManager = require('src/bidmanager'); - - -describe("sekindoUM Adapter Tests", () => { - - let _sekindoUMAdapter; - var addBidResponseSpy; - - const bidderRequest = { - bidderCode: 'sekindoUM', - bids: [{ - bidder: 'sekindoUM', - bidId: 'sekindo_bidId', - bidderRequestId: 'sekindo_bidderRequestId', - requestId: 'sekindo_requestId', - placementCode: 'foo', - params: { - spaceId: 14071 - } - }] - }; - - beforeEach(() => { - _sekindoUMAdapter = new sekindoUMAdapter(); - }); - - describe('sekindoUM callBids', () => { - - beforeEach(() => { - _sekindoUMAdapter.callBids(bidderRequest); - }); - - it('Verify sekindo script tag was created', () => { - var scriptTags = document.getElementsByTagName('script'); - var sekindoTagExists=0; - for (var i=0; itest ad' - }; - - $$PREBID_GLOBAL$$.sekindoCB(bidderRequest.bids[0].bidId, HB_bid); - var firstBid = addBidResponseSpy.getCall(0).args[1]; - var placementCode1 = addBidResponseSpy.getCall(0).args[0]; - - expect(firstBid.getStatusCode()).to.equal(1); - expect(firstBid.bidderCode).to.equal('sekindoUM'); - expect(firstBid.cpm).to.equal(0.23); - expect(firstBid.ad).to.equal('

test ad

'); - expect(placementCode1).to.equal('foo'); - - expect(addBidResponseSpy.getCalls().length).to.equal(1); - }); - }); - -}); diff --git a/test/spec/adapters/smartadserver_spec.js b/test/spec/adapters/smartadserver_spec.js deleted file mode 100644 index f48f10d9cb5..00000000000 --- a/test/spec/adapters/smartadserver_spec.js +++ /dev/null @@ -1,152 +0,0 @@ -describe("smartadserver adapter tests", function () { - var urlParse = require("url-parse"); - var querystringify = require("querystringify"); - var adapter = require("src/adapters/smartadserver"); - var adLoader = require("src/adloader"); - var expect = require("chai").expect; - var bidmanager = require("src/bidmanager"); - var CONSTANTS = require('src/constants.json'); - - var DEFAULT_PARAMS = { - bidderCode: "smartadserver", - bids: [{ - bidId: "abcd1234", - sizes: [[300, 250], [300, 200]], - bidder: "smartadserver", - params: { - domain: "http://www.smartadserver.com", - siteId: "1234", - pageId: "5678", - formatId: "90", - target: "test=prebid", - currency: "EUR" - }, - requestId: "efgh5678", - placementCode: "sas_42" - } - ] - }; - - var DEFAULT_PARAMS_WO_OPTIONAL = { - bidderCode: "smartadserver", - bids: [{ - bidId: "abcd1234", - sizes: [[300, 250], [300, 200]], - bidder: "smartadserver", - params: { - domain: "http://www.smartadserver.com", - siteId: "1234", - pageId: "5678", - formatId: "90" - }, - requestId: "efgh5678", - placementCode: "sas_42" - } - ] - }; - - var BID_RESPONSE = { - cpm: 0.42, - ad: "fake ad content", - width: 300, - height: 250 - }; - - it("set url parameters", function () { - var stubLoadScript = sinon.stub(adLoader, "loadScript"); - - adapter().callBids(DEFAULT_PARAMS); - - var smartCallback; - for (var k in $$PREBID_GLOBAL$$) { - if (k.lastIndexOf("sas_", 0) === 0) { - smartCallback = k; - break; - } - } - - var bidUrl = stubLoadScript.getCall(0).args[0]; - var parsedBidUrl = urlParse(bidUrl); - var parsedBidUrlQueryString = querystringify.parse(parsedBidUrl.query); - - expect(parsedBidUrl.hostname).to.equal("www.smartadserver.com"); - expect(parsedBidUrl.pathname).to.equal("/prebid"); - - expect(parsedBidUrlQueryString).to.have.property("pbjscbk").and.to.equal("pbjs." + smartCallback); - expect(parsedBidUrlQueryString).to.have.property("siteid").and.to.equal("1234"); - expect(parsedBidUrlQueryString).to.have.property("pgid").and.to.equal("5678"); - expect(parsedBidUrlQueryString).to.have.property("fmtid").and.to.equal("90"); - expect(parsedBidUrlQueryString).to.have.property("tgt").and.to.equal("test=prebid"); - expect(parsedBidUrlQueryString).to.have.property("ccy").and.to.equal("EUR"); - expect(parsedBidUrlQueryString).to.have.property("tag").and.to.equal("sas_42"); - expect(parsedBidUrlQueryString).to.have.property("sizes").and.to.equal("300x250,300x200"); - expect(parsedBidUrlQueryString).to.have.property("async").and.to.equal("1"); - - stubLoadScript.restore(); - }); - - it("test optional parameters default value", function () { - var stubLoadScript = sinon.stub(adLoader, "loadScript"); - - adapter().callBids(DEFAULT_PARAMS_WO_OPTIONAL); - - var bidUrl = stubLoadScript.getCall(0).args[0]; - var parsedBidUrl = urlParse(bidUrl); - var parsedBidUrlQueryString = querystringify.parse(parsedBidUrl.query); - - expect(parsedBidUrlQueryString).to.have.property("tgt").and.to.equal(""); - expect(parsedBidUrlQueryString).to.have.property("ccy").and.to.equal("USD"); - - stubLoadScript.restore(); - }); - - it("creates an empty bid response if no bids", function() { - var stubLoadScript = sinon.stub(adLoader, "loadScript", function(url) { - var bidUrl = stubLoadScript.getCall(0).args[0]; - var parsedBidUrl = urlParse(bidUrl); - var parsedBidUrlQueryString = querystringify.parse(parsedBidUrl.query); - - pbjs[parsedBidUrlQueryString.pbjscbk.split(".")[1]](null); - }); - var stubAddBidResponse = sinon.stub(bidmanager, "addBidResponse"); - - adapter().callBids(DEFAULT_PARAMS); - - var bidResponsePlacementCode = stubAddBidResponse.getCall(0).args[0]; - var bidResponseAd = stubAddBidResponse.getCall(0).args[1]; - - expect(bidResponsePlacementCode).to.equal(DEFAULT_PARAMS.bids[0].placementCode); - expect(bidResponseAd.getStatusCode()).to.equal(CONSTANTS.STATUS.NO_BID); - expect(bidResponseAd).to.have.property("bidderCode").and.to.equal("smartadserver"); - - stubLoadScript.restore(); - stubAddBidResponse.restore(); - }); - - it("creates a bid response if bid is returned", function() { - var stubLoadScript = sinon.stub(adLoader, "loadScript", function(url) { - var bidUrl = stubLoadScript.getCall(0).args[0]; - var parsedBidUrl = urlParse(bidUrl); - var parsedBidUrlQueryString = querystringify.parse(parsedBidUrl.query); - - pbjs[parsedBidUrlQueryString.pbjscbk.split(".")[1]](BID_RESPONSE); - }); - var stubAddBidResponse = sinon.stub(bidmanager, "addBidResponse"); - - adapter().callBids(DEFAULT_PARAMS); - - var bidResponsePlacementCode = stubAddBidResponse.getCall(0).args[0]; - var bidResponseAd = stubAddBidResponse.getCall(0).args[1]; - - expect(bidResponsePlacementCode).to.equal(DEFAULT_PARAMS.bids[0].placementCode); - expect(bidResponseAd.getStatusCode()).to.equal(CONSTANTS.STATUS.GOOD); - expect(bidResponseAd).to.have.property("bidderCode").and.to.equal("smartadserver"); - expect(bidResponseAd).to.have.property("cpm").and.to.equal(BID_RESPONSE.cpm); - expect(bidResponseAd).to.have.property("ad").and.to.equal(BID_RESPONSE.ad); - expect(bidResponseAd).to.have.property("width").and.to.equal(BID_RESPONSE.width); - expect(bidResponseAd).to.have.property("height").and.to.equal(BID_RESPONSE.height); - - stubLoadScript.restore(); - stubAddBidResponse.restore(); - }); -}); diff --git a/test/spec/adapters/smartyads_spec.js b/test/spec/adapters/smartyads_spec.js deleted file mode 100644 index 357599e69cd..00000000000 --- a/test/spec/adapters/smartyads_spec.js +++ /dev/null @@ -1,131 +0,0 @@ -import { expect } from 'chai'; -import Adapter from '../../../src/adapters/smartyads'; -import adapterManager from 'src/adaptermanager'; -import bidManager from 'src/bidmanager'; -import CONSTANTS from 'src/constants.json'; - -describe('Smartyads adapter tests', function () { - - let sandbox; - const adUnit = { // TODO CHANGE - code: 'smartyads', - sizes: [[300, 250], [300,600], [320, 80]], - bids: [{ - bidder: 'smartyads', - params: { - banner_id: 0 - } - }] - }; - - const response = { - ad_id: 0, - adm: "Test Response", - cpm: 0.5, - deal: "bf063e2e025c", - height: 240, - width: 360 - }; - - beforeEach(() => { - sandbox = sinon.sandbox.create(); - }); - - afterEach(() => { - sandbox.restore(); - }); - - describe('Smartyads callBids validation', () => { - - let bids, - server; - - beforeEach(() => { - bids = []; - server = sinon.fakeServer.create(); - - sandbox.stub(bidManager, 'addBidResponse', (elemId, bid) => { - bids.push(bid); - }); - }); - - afterEach(() => { - server.restore(); - }); - - let adapter = adapterManager.bidderRegistry['smartyads']; - - it('Valid bid-request', () => { - sandbox.stub(adapter, 'callBids'); - adapterManager.callBids({ - adUnits: [clone(adUnit)] - }); - - let bidderRequest = adapter.callBids.getCall(0).args[0]; - - expect(bidderRequest).to.have.property('bids') - .that.is.an('array') - .with.lengthOf(1); - - expect(bidderRequest).to.have.deep.property('bids[0]') - .to.have.property('bidder', 'smartyads'); - - expect(bidderRequest).to.have.deep.property('bids[0]') - .with.property('sizes') - .that.is.an('array') - .with.lengthOf(3) - .that.deep.equals(adUnit.sizes); - expect(bidderRequest).to.have.deep.property('bids[0]') - .with.property('params') - .to.have.property('banner_id', 0); - }); - - it('Valid bid-response', ()=>{ - server.respondWith(JSON.stringify( - response - )); - adapterManager.callBids({ - adUnits: [clone(adUnit)] - }); - server.respond(); - - expect(bids).to.be.lengthOf(1); - expect(bids[0].getStatusCode()).to.equal(CONSTANTS.STATUS.GOOD); - expect(bids[0].bidderCode).to.equal("smartyads"); - expect(bids[0].width).to.equal(360); - expect(bids[0].height).to.equal(240); - expect(bids[0].cpm).to.equal(0.5); - expect(bids[0].dealId).to.equal("bf063e2e025c"); - }); - }); - - describe('MAS mapping / ordering', () => { - - let masSizeOrdering = Adapter.masSizeOrdering; - - it('should not include values without a proper mapping', () => { - let ordering = masSizeOrdering([[320, 50], [42, 42], [300, 250], [640, 480], [1, 1], [336, 280]]); - expect(ordering).to.deep.equal([15, 16, 43, 65]); - }); - - it('should sort values without any MAS priority sizes in regular ascending order', () => { - let ordering = masSizeOrdering([[320, 50], [640, 480], [336, 280], [200, 600]]); - expect(ordering).to.deep.equal([16, 43, 65, 126]); - }); - - it('should sort MAS priority sizes in the proper order w/ rest ascending', () => { - let ordering = masSizeOrdering([[320, 50], [160,600], [640, 480], [300, 250],[336, 280], [200, 600]]); - expect(ordering).to.deep.equal([15, 9, 16, 43, 65, 126]); - - ordering = masSizeOrdering([[320, 50], [300, 250], [160,600], [640, 480],[336, 280], [200, 600], [728, 90]]); - expect(ordering).to.deep.equal([15, 2, 9, 16, 43, 65, 126]); - - ordering = masSizeOrdering([[120, 600], [320, 50], [160,600], [640, 480],[336, 280], [200, 600], [728, 90]]); - expect(ordering).to.deep.equal([2, 9, 8, 16, 43, 65, 126]); - }) - }); -}); - -function clone(obj) { - return JSON.parse(JSON.stringify(obj)); -} \ No newline at end of file diff --git a/test/spec/adapters/stickyadstv_spec.js b/test/spec/adapters/stickyadstv_spec.js deleted file mode 100644 index b485416f614..00000000000 --- a/test/spec/adapters/stickyadstv_spec.js +++ /dev/null @@ -1,219 +0,0 @@ -import {expect} from 'chai'; -import {assert} from 'chai'; -import Adapter from '../../../src/adapters/stickyadstv'; -import bidManager from '../../../src/bidmanager'; -import adLoader from '../../../src/adloader'; - -describe('StickyAdsTV Adapter', function () { - var adapter = void 0; - var sandbox = void 0; - var bidsRequestBuff = void 0; - var bidderRequest = { - bidderCode: 'stickyadstv', - bids: [{ - bidId: 'bidId1', - bidder: 'stickyadstv', - placementCode: 'foo', - sizes: [[300, 250]], - params: { - zoneId: '2003', - format:"screen-roll" - } - }, { - bidId: 'bidId2', - bidder: 'stickyadstv', - placementCode: 'bar', - sizes: [[728, 90]], - params: { - zoneId: '5562003' - } - }, { - bidId: 'bidId3', - bidder: 'stickyadstv', - placementCode: '', - sizes: [[300, 600]], - params: { - zoneId: '123456' - } - }, { - bidId: 'bidId4', - bidder: 'stickyadstv', - placementCode: 'coo', - sizes: [[300, 600]], - params: { - wrong: "missing zoneId" - } - }] - }; - - beforeEach(function () { - adapter = new Adapter(); - sandbox = sinon.sandbox.create(); - bidsRequestBuff = pbjs._bidsRequested; - pbjs._bidsRequested = []; - }); - - afterEach(function () { - sandbox.restore(); - pbjs._bidsRequested = bidsRequestBuff; - }); - - describe('callBids', function () { - beforeEach(function () { - sandbox.stub(adLoader, 'loadScript'); - adapter.callBids(bidderRequest); - }); - - it('should be called twice', function () { - sinon.assert.calledTwice(adLoader.loadScript); - }); - - it('should have load screenroll and mustang script', function () { - var url = void 0; - - url = adLoader.loadScript.firstCall.args[0]; - expect(url).to.equal("//cdn.stickyadstv.com/prime-time/screen-roll.min.js"); - - url = adLoader.loadScript.secondCall.args[0]; - expect(url).to.equal("//cdn.stickyadstv.com/mustang/mustang.min.js"); - }); - }); - - describe('getBid', function () { - let bidResponse; - let loadConfig; - let getPricingCalled; - - beforeEach(function () { - //Mock VastLoader for test purpose - window.com = { - stickyadstv : { - vast : { - VastLoader : function(){ - this.getVast = function(){ - return { - getPricing : function(){ - getPricingCalled = true; - return {currency:"USD", price: 4.000} - } - }; - }; - - this.load = function(config, listener){ - loadConfig = config; - listener.onSuccess(); - }; - } - }, - screenroll : { - getPlayerSize: function(){ - return "123x456"; - } - } - } - }; - - adapter.getBid(bidderRequest.bids[0], function(bidObject){ - bidResponse = bidObject; - }); - }); - - afterEach(function() { - delete window.com.stickyadstv.vast.VastLoader; - delete window.com.stickyadstv.vast; - delete window.com.stickyadstv.screenroll; - delete window.com.stickyadstv; - }); - - it('should have returned a valid bidObject', function () { - - expect(bidResponse).to.have.property('cpm', 4.000); - expect(bidResponse).to.have.property('ad', ""); - expect(bidResponse).to.have.property('bidderCode', "stickyadstv"); - expect(bidResponse).to.have.property('currencyCode', "USD"); - expect(bidResponse).to.have.property('width', 300); - expect(bidResponse).to.have.property('height', 250); - expect(bidResponse.getStatusCode()).to.equal(1); - }); - - it('should have called load with proper config', function () { - - expect(loadConfig).to.have.property('playerSize', "123x456"); - expect(loadConfig).to.have.property('zoneId', "2003"); - - }); - - it('should have called getPricing', function () { - - expect(getPricingCalled).to.equal(true); - - }); - }); - - describe('formatBidObject', function () { - - it('should create a valid bid object', function () { - let result = adapter.formatBidObject("", true, {currency:"EUR",price:"1.2345"}, "
sample
", 200, 300); - - expect(result).to.have.property('cpm', '1.2345'); - expect(result).to.have.property('ad', "
sample
"); - expect(result).to.have.property('currencyCode', "EUR"); - expect(result).to.have.property('width', 200); - expect(result).to.have.property('height', 300); - expect(result.getStatusCode()).to.equal(1); - }); - - it('should create a invalid bid object because price is not defined', function () { - let result = adapter.formatBidObject("", true, null, "
sample
", 200, 300); - - expect(result.getStatusCode()).to.equal(2); - }); - - it('should create a invalid bid object', function () { - let result = adapter.formatBidObject("", false, {currency:"EUR",price:"1.2345"}, "
sample
", 200, 300); - - expect(result.getStatusCode()).to.equal(2); - }); - }); - - describe('formatAdHTML', function () { - - it('should create an inBanner ad format', function () { - let result = adapter.formatAdHTML({placementCode:"placementCodeValue", params:{}}, [200,300]); - - expect(result).to.equal('
'); - }); - - it('should create an intext ad format', function () { - let result = adapter.formatAdHTML({placementCode:"placementCodeValue", params:{format:"intext-roll", auto:"v2", smartPlay:"true"}}, [200,300]); - - expect(result).to.equal(''); - }); - - it('should create a screenroll ad format', function () { - let result = adapter.formatAdHTML({placementCode:"placementCodeValue", params:{format:"screen-roll", smartPlay:"true"}}, [200,300]); - - expect(result).to.equal(''); - }); - }); - - describe('getBiggerSize', function () { - - it('should returns the bigger size', function () { - let result = adapter.getBiggerSize([[1,4000],[4000,1],[200,300],[0,0]]); - - expect(result[0]).to.equal(200); - expect(result[1]).to.equal(300); - }); - }); - - describe('top most window', function () { - - it('should returns the top most window', function () { - let result = adapter.getTopMostWindow(); - - expect(result).to.equal(window.top); - }); - }); - -}); \ No newline at end of file diff --git a/test/spec/adapters/twenga_spec.js b/test/spec/adapters/twenga_spec.js deleted file mode 100644 index 141b4c4e22b..00000000000 --- a/test/spec/adapters/twenga_spec.js +++ /dev/null @@ -1,120 +0,0 @@ -describe("twenga adapter tests", function () { - - var urlParse = require("url-parse"); - var querystringify = require("querystringify"); - var adapter = require("src/adapters/twenga"); - var adLoader = require("src/adloader"); - var expect = require("chai").expect; - var bidmanager = require("src/bidmanager"); - var CONSTANTS = require('src/constants.json'); - - var DEFAULT_PARAMS = { - bidderCode: "twenga", - bids: [{ - bidId: "tw_abcd1234", - sizes: [[300, 250], [300, 200]], - bidder: "twenga", - params: { - placementId: "test", - siteId: 1234, - publisherId: 5678, - currency: "USD", - bidFloor: 0.5, - country: "DE" - }, - requestId: "tw_efgh5678", - placementCode: "tw_42" - }] - }; - - var BID_RESPONSE = { - result: { - cpm: 10000, - width: 300, - height: 250, - ad: "//rtb.t.c4tw.net", - creative_id: "test" - }, - callback_uid: "tw_abcd1234" - }; - - it("sets url parameters", function () { - var stubLoadScript = sinon.stub(adLoader, "loadScript"); - - adapter().callBids(DEFAULT_PARAMS); - - var bidUrl = stubLoadScript.getCall(0).args[0]; - var parsedBidUrl = urlParse(bidUrl); - var parsedBidUrlQueryString = querystringify.parse(parsedBidUrl.query); - - expect(parsedBidUrl.hostname).to.equal("rtb.t.c4tw.net"); - expect(parsedBidUrl.pathname).to.equal("/Bid"); - - expect(parsedBidUrlQueryString).to.have.property("s").and.to.equal("h"); - expect(parsedBidUrlQueryString).to.have.property("callback").and.to.equal("$$PREBID_GLOBAL$$.handleTwCB"); - expect(parsedBidUrlQueryString).to.have.property("callback_uid").and.to.equal("tw_abcd1234"); - expect(parsedBidUrlQueryString).to.have.property("id").and.to.equal("test"); - - stubLoadScript.restore(); - }); - - var stringToFunction = function (s) { - var scope = global; - var scopeSplit = s.split('.'); - for (var i = 0; i < scopeSplit.length - 1; i++) { - scope = scope[scopeSplit[i]]; - if (scope == undefined) return; - } - return scope[scopeSplit[scopeSplit.length - 1]]; - }; - - it("creates an empty bid response if no bids", function() { - var stubLoadScript = sinon.stub(adLoader, "loadScript", function(url) { - var bidUrl = stubLoadScript.getCall(0).args[0]; - var parsedBidUrl = urlParse(bidUrl); - var parsedBidUrlQueryString = querystringify.parse(parsedBidUrl.query); - - var callback = stringToFunction(parsedBidUrlQueryString.callback); - expect(callback).to.exist.and.to.be.a('function'); - callback(undefined); - }); - var stubAddBidResponse = sinon.stub(bidmanager, "addBidResponse"); - - adapter.createNew().callBids(DEFAULT_PARAMS); - - expect(stubAddBidResponse.getCall(0)).to.be.null; - - stubAddBidResponse.restore(); - stubLoadScript.restore(); - }); - - it("creates a bid response if bid is returned", function() { - var stubLoadScript = sinon.stub(adLoader, "loadScript", function(url) { - var bidUrl = stubLoadScript.getCall(0).args[0]; - var parsedBidUrl = urlParse(bidUrl); - var parsedBidUrlQueryString = querystringify.parse(parsedBidUrl.query); - - $$PREBID_GLOBAL$$._bidsRequested. - push({ bidderCode: DEFAULT_PARAMS.bidderCode, - bids: [{ bidId: parsedBidUrlQueryString.callback_uid, - placementCode: DEFAULT_PARAMS.bids[0].placementCode }]}); - - var callback = stringToFunction(parsedBidUrlQueryString.callback); - expect(callback).to.exist.and.to.be.a('function'); - callback(BID_RESPONSE); - }); - var stubAddBidResponse = sinon.stub(bidmanager, "addBidResponse"); - - adapter.createNew().callBids(DEFAULT_PARAMS); - - var bidResponseAd = stubAddBidResponse.getCall(0).args[1]; - - expect(bidResponseAd).to.have.property("cpm").and.to.equal(BID_RESPONSE.result.cpm / 10000); - expect(bidResponseAd).to.have.property("adUrl").and.to.equal(BID_RESPONSE.result.ad); - expect(bidResponseAd).to.have.property("width").and.to.equal(BID_RESPONSE.result.width); - expect(bidResponseAd).to.have.property("height").and.to.equal(BID_RESPONSE.result.height); - - stubAddBidResponse.restore(); - stubLoadScript.restore(); - }); -}); diff --git a/test/spec/adapters/vertamedia_spec.js b/test/spec/adapters/vertamedia_spec.js deleted file mode 100644 index 2b6e9e466e4..00000000000 --- a/test/spec/adapters/vertamedia_spec.js +++ /dev/null @@ -1,147 +0,0 @@ -import { expect } from 'chai'; -import Adapter from 'src/adapters/vertamedia'; -import bidmanager from 'src/bidmanager'; - -const ENDPOINT = 'http://rtb.vertamedia.com/hb/?aid=22489&w=640&h=480&domain=localhost'; - -const REQUEST = { - "bidderCode": "vertamedia", - "requestId": "d3e07445-ab06-44c8-a9dd-5ef9af06d2a6", - "bidderRequestId": "7101db09af0db2", - "bids": [ - { - "bidder": "vertamedia", - "params": { - aid: 22489, - placementId: '123456' - }, - "placementCode": "/19968336/header-bid-tag1", - "sizes": [640, 480], - "bidId": "84ab500420319d", - "bidderRequestId": "7101db09af0db2", - "requestId": "d3e07445-ab06-44c8-a9dd-5ef9af06d2a6" - } - ], - "start": 1469479810130 -}; -var RESPONSE = { - "source": { - "aid": 22489, - "pubId": 18016, - "sid": "0" - }, - "bids": [ - { - "cmpId": 9541, - "cpm": 4.5, - "url": "http://rtb.vertamedia.com/vast?adid=BFDB9CC0038AD918", - "cur": "USD" - } - ] -}; - - -describe('VertamediaAdater', () => { - - let adapter; - - beforeEach(() => adapter = Adapter.createNew()); - - describe('request function', () => { - - let xhr; - let requests; - - beforeEach(() => { - xhr = sinon.useFakeXMLHttpRequest(); - requests = []; - xhr.onCreate = request => requests.push(request); - }); - - afterEach(() => xhr.restore()); - - it('exists and is a function', () => { - expect(adapter.callBids).to.exist.and.to.be.a('function'); - }); - - it('requires paramters to make request', () => { - adapter.callBids({}); - expect(requests).to.be.empty; - }); - - it('requires member && invCode', () => { - let backup = REQUEST.bids[0].params; - REQUEST.bids[0].params = {member: 1234}; - adapter.callBids(REQUEST); - expect(requests).to.be.empty; - REQUEST.bids[0].params = backup; - }); - - - it('sends bid request to ENDPOINT via POST', () => { - adapter.callBids(REQUEST); - expect(requests[0].url).to.equal(ENDPOINT); - expect(requests[0].method).to.equal('GET'); - }); - - }); - - describe('response handler', () => { - - let server; - - beforeEach(() => { - server = sinon.fakeServer.create(); - sinon.stub(bidmanager, 'addBidResponse'); - }); - - afterEach(() => { - server.restore(); - bidmanager.addBidResponse.restore(); - }); - - it('registers bids', () => { - server.respondWith(JSON.stringify(RESPONSE)); - - adapter.callBids(REQUEST); - server.respond(); - sinon.assert.calledOnce(bidmanager.addBidResponse); - - const response = bidmanager.addBidResponse.firstCall.args[1]; - expect(response).to.have.property('statusMessage', 'Bid available'); - expect(response).to.have.property('cpm', 4.5); - }); - - it('handles nobid responses', () => { - server.respondWith(JSON.stringify({ - aid: 356465468, - w: 640, - h: 480, - domain: 'localhost' - })); - - adapter.callBids(REQUEST); - server.respond(); - sinon.assert.calledOnce(bidmanager.addBidResponse); - - const response = bidmanager.addBidResponse.firstCall.args[1]; - expect(response).to.have.property( - 'statusMessage', - 'Bid returned empty or error response' - ); - }); - - it('handles JSON.parse errors', () => { - server.respondWith(''); - - adapter.callBids(REQUEST); - server.respond(); - sinon.assert.calledOnce(bidmanager.addBidResponse); - - expect(bidmanager.addBidResponse.firstCall.args[1]).to.have.property( - 'statusMessage', - 'Bid returned empty or error response' - ); - }); - }); -}); diff --git a/test/spec/adapters/vertoz_spec.js b/test/spec/adapters/vertoz_spec.js deleted file mode 100755 index 76ef50ad7a3..00000000000 --- a/test/spec/adapters/vertoz_spec.js +++ /dev/null @@ -1,145 +0,0 @@ -import {expect} from 'chai'; -import {assert} from 'chai'; -import Adapter from '../../../src/adapters/vertoz'; -import bidManager from '../../../src/bidmanager'; -import adLoader from '../../../src/adloader'; - -describe('Vertoz Adapter', () => { - let adapter; - let sandbox; - let bidsRequestBuff; - const bidderRequest = { - bidderCode: 'vertoz', - bids: [{ - bidId: 'bidId1', - bidder: 'vertoz', - placementCode: 'foo', - sizes: [ - [300, 250] - ], - params: { - placementId: 'VZ-HB-123' - } - },{ - bidId: 'bidId2', - bidder: 'vertoz', - placementCode: 'bar', - sizes: [ - [728, 90] - ], - params: { - placementId: 'VZ-HB-456' - } - },{ - bidId: 'bidId3', - bidder: 'vertoz', - placementCode: 'coo', - sizes: [ - [300, 600] - ], - params: { - placementId: '' - } - }] - }; - - beforeEach(() => { - adapter = new Adapter(); - sandbox = sinon.sandbox.create(); - bidsRequestBuff = pbjs._bidsRequested; - pbjs._bidsRequested = []; - }); - - afterEach(() => { - sandbox.restore(); - pbjs._bidsRequested = bidsRequestBuff; - }); - - describe('callBids', () => { - beforeEach(() => { - sandbox.stub(adLoader, 'loadScript'); - adapter.callBids(bidderRequest); - }); - - it('should be called twice', () => { - sinon.assert.calledTwice(adLoader.loadScript); - }); - - }); - - describe('Bid response', () => { - let vzBidRequest; - let bidderReponse = { - "vzhPlacementId": "VZ-HB-123", - "bid": "0fac1b8a-6ba0-4641-bd57-2899b1bedeae_0", - "adWidth": "300", - "adHeight": "250", - "cpm": "1.00000000000000", - "ad": "
", - "slotBidId": "bidId1", - "nurl": "", - "statusText": "vertoz:success" - }; - - beforeEach(() => { - pbjs._bidsRequested.push(bidderRequest); - }); - - describe('success', () => { - let firstBidReg; - let adSpaceId; - - beforeEach(() => { - sandbox.stub(bidManager, 'addBidResponse'); - pbjs.vzResponse(bidderReponse); - firstBidReg = bidManager.addBidResponse.firstCall.args[1]; - adSpaceId = bidManager.addBidResponse.firstCall.args[0]; - }); - - it('cpm to have property 1.000000', () => { - expect(firstBidReg).to.have.property('cpm', 1.00); - }); - it('adSpaceId should exist and be equal to placementCode', () => { - expect(adSpaceId).to.equal("foo"); - }); - it('should have property ad', () => { - expect(firstBidReg).to.have.property('ad'); - }); - it('should include the size to the bid object', () => { - expect(firstBidReg).to.have.property('width', '300'); - expect(firstBidReg).to.have.property('height', '250'); - }); - - }); - - describe('failure', () => { - let secondBidReg; - let adSpaceId; - let bidderResponse = { - "vzhPlacementId": "VZ-HB-456", - "slotBidId": "bidId2", - "statusText": "vertoz:NO_BIDS" - } - - beforeEach(() => { - sandbox.stub(bidManager, 'addBidResponse'); - pbjs.vzResponse(bidderResponse); - secondBidReg = bidManager.addBidResponse.firstCall.args[1]; - adSpaceId = bidManager.addBidResponse.firstCall.args[0]; - }); - - it('should not have cpm property', () => { - expect(secondBidReg.cpm).to.be.undefined; - }); - it('adSpaceId should exist and be equal to placementCode', () => { - expect(adSpaceId).to.equal("bar"); - }); - it('should not have ad property', () => { - expect(secondBidReg.ad).to.be.undefined; - }); - - }); - - }); - -}); diff --git a/test/spec/adapters/wideorbit_spec.js b/test/spec/adapters/wideorbit_spec.js deleted file mode 100644 index 552f8c39cdc..00000000000 --- a/test/spec/adapters/wideorbit_spec.js +++ /dev/null @@ -1,513 +0,0 @@ -describe('wideorbit adapter tests', function () { - - var expect = require('chai').expect; - var urlParse = require('url-parse'); - - // FYI: querystringify will perform encoding/decoding - var querystringify = require('querystringify'); - - var adapter = require('src/adapters/wideorbit'); - var adLoader = require('src/adloader'); - var bidmanager = require('src/bidmanager'); - - describe('creation of bid url', function () { - - let stubLoadScript; - - beforeEach(function () { - stubLoadScript = sinon.stub(adLoader, 'loadScript'); - }); - - afterEach(function () { - stubLoadScript.restore(); - }); - - it('should be called only once', function () { - - var params = { - bidderCode: 'wideorbit', - bids: [ - { - bidder: 'wideorbit', - params: { - pbId: 1, - pId: 101 - }, - placementCode: 'div-gpt-ad-12345-1' - }, - { - bidder: 'wideorbit', - params: { - pbId: 1, - site: 'Site 1', - page: 'Page 1', - width: 100, - height: 200, - subPublisher: 'Sub Publisher 1' - }, - placementCode: 'div-gpt-ad-12345-2' - } - ] - }; - - adapter().callBids(params); - - sinon.assert.calledOnce(stubLoadScript); - - }); - - it('should fix parameters name', function () { - - var params = { - bidderCode: 'wideorbit', - bids: [ - { - bidder: 'wideorbit', - params: { - PBiD: 1, - PID: 101, - ReferRer: 'http://www.foo.com?param1=param1¶m2=param2' - }, - placementCode: 'div-gpt-ad-12345-1' - }, - { - bidder: 'wideorbit', - params: { - pbid: 1, - SiTe: 'Site 1', - Page: 'Page 1', - widTH: 100, - HEIGHT: 200, - SUBPublisher: 'Sub Publisher 1' - }, - placementCode: 'div-gpt-ad-12345-2' - } - ] - }; - - adapter().callBids(params); - - var bidUrl = stubLoadScript.getCall(0).args[0]; - - sinon.assert.calledWith(stubLoadScript, bidUrl); - - var parsedBidUrl = urlParse(bidUrl); - var parsedBidUrlQueryString = querystringify.parse(parsedBidUrl.query); - - expect(parsedBidUrl.hostname).to.equal('p1.atemda.com') - expect(parsedBidUrl.pathname).to.equal('/JSAdservingMP.ashx') - expect(parsedBidUrlQueryString).to.have.property('pc').and.to.equal('2'); - expect(parsedBidUrlQueryString).to.have.property('pbId').and.to.equal('1'); - expect(parsedBidUrlQueryString).to.have.property('jsv').and.to.equal('1.0'); - expect(parsedBidUrlQueryString).to.have.property('tsv').and.to.equal('1.0'); - expect(parsedBidUrlQueryString).to.have.property('cts').to.have.length.above(0); - expect(parsedBidUrlQueryString).to.have.property('arp').and.to.equal('0'); - expect(parsedBidUrlQueryString).to.have.property('fl').and.to.equal('0'); - expect(parsedBidUrlQueryString).to.have.property('jscb').and.to.equal('window.$$PREBID_GLOBAL$$.handleWideOrbitCallback'); - expect(parsedBidUrlQueryString).to.have.property('mpp').and.to.equal('0'); - expect(parsedBidUrlQueryString).to.have.property('cb').to.have.length.above(0); - expect(parsedBidUrlQueryString).to.have.property('hb').and.to.equal('1'); - expect(parsedBidUrlQueryString).to.have.property('url').and.to.equal('http://www.foo.com?param1=param1¶m2=param2'); - - expect(parsedBidUrlQueryString).to.have.property('gid0').and.to.equal('div-gpt-ad-12345-1'); - expect(parsedBidUrlQueryString).to.have.property('rpos0').and.to.equal('0'); - expect(parsedBidUrlQueryString).to.have.property('ecpm0').and.to.equal(''); - - expect(parsedBidUrlQueryString).to.have.property('gid1').and.to.equal('div-gpt-ad-12345-2'); - expect(parsedBidUrlQueryString).to.have.property('rpos1').and.to.equal('0'); - expect(parsedBidUrlQueryString).to.have.property('ecpm1').and.to.equal(''); - - expect(parsedBidUrlQueryString).to.have.property('pId0').and.to.equal('101'); - expect(parsedBidUrlQueryString).to.have.property('rank0').and.to.equal('0'); - - expect(parsedBidUrlQueryString).to.have.property('wsName1').and.to.equal('Site 1'); - expect(parsedBidUrlQueryString).to.have.property('wName1').and.to.equal('Page 1'); - expect(parsedBidUrlQueryString).to.have.property('rank1').and.to.equal('1'); - expect(parsedBidUrlQueryString).to.have.property('bfDim1').and.to.equal('100x200'); - expect(parsedBidUrlQueryString).to.have.property('subp1').and.to.equal('Sub Publisher 1'); - - }); - - describe('placement by name', function () { - - it('should be called with specific parameters for two bids', function () { - - var params = { - bidderCode: 'wideorbit', - bids: [ - { - bidder: 'wideorbit', - params: { - pbId: 1, - site: 'Site 1', - page: 'Page 1', - width: 100, - height: 200, - subPublisher: 'Sub Publisher 1', - atf: true - }, - placementCode: 'div-gpt-ad-12345-1' - }, - { - bidder: 'wideorbit', - params: { - pbId: 1, - site: 'Site 2', - page: 'Page 2', - width: 200, - height: 300, - rank: 123, - ecpm: 1.8 - }, - placementCode: 'div-gpt-ad-12345-2' - } - ] - }; - - adapter().callBids(params); - - var bidUrl = stubLoadScript.getCall(0).args[0]; - - sinon.assert.calledWith(stubLoadScript, bidUrl); - - var parsedBidUrl = urlParse(bidUrl); - var parsedBidUrlQueryString = querystringify.parse(parsedBidUrl.query); - - expect(parsedBidUrl.hostname).to.equal('p1.atemda.com') - expect(parsedBidUrl.pathname).to.equal('/JSAdservingMP.ashx') - expect(parsedBidUrlQueryString).to.have.property('pc').and.to.equal('2'); - expect(parsedBidUrlQueryString).to.have.property('pbId').and.to.equal('1'); - expect(parsedBidUrlQueryString).to.have.property('jsv').and.to.equal('1.0'); - expect(parsedBidUrlQueryString).to.have.property('tsv').and.to.equal('1.0'); - expect(parsedBidUrlQueryString).to.have.property('cts').to.have.length.above(0); - expect(parsedBidUrlQueryString).to.have.property('arp').and.to.equal('0'); - expect(parsedBidUrlQueryString).to.have.property('fl').and.to.equal('0'); - expect(parsedBidUrlQueryString).to.have.property('jscb').and.to.equal('window.$$PREBID_GLOBAL$$.handleWideOrbitCallback'); - expect(parsedBidUrlQueryString).to.have.property('mpp').and.to.equal('0'); - expect(parsedBidUrlQueryString).to.have.property('cb').to.have.length.above(0); - expect(parsedBidUrlQueryString).to.have.property('hb').and.to.equal('1'); - expect(parsedBidUrlQueryString).to.have.property('url').and.to.be.empty; - - expect(parsedBidUrlQueryString).to.have.property('gid0').and.to.equal('div-gpt-ad-12345-1'); - expect(parsedBidUrlQueryString).to.have.property('rpos0').and.to.equal('1001'); - expect(parsedBidUrlQueryString).to.have.property('ecpm0').and.to.equal(''); - - expect(parsedBidUrlQueryString).to.have.property('gid1').and.to.equal('div-gpt-ad-12345-2'); - expect(parsedBidUrlQueryString).to.have.property('rpos1').and.to.equal('0'); - expect(parsedBidUrlQueryString).to.have.property('ecpm1').and.to.equal('1.8'); - - expect(parsedBidUrlQueryString).to.have.property('wsName0').and.to.equal('Site 1'); - expect(parsedBidUrlQueryString).to.have.property('wName0').and.to.equal('Page 1'); - expect(parsedBidUrlQueryString).to.have.property('rank0').and.to.equal('0'); - expect(parsedBidUrlQueryString).to.have.property('bfDim0').and.to.equal('100x200'); - expect(parsedBidUrlQueryString).to.have.property('subp0').and.to.equal('Sub Publisher 1'); - - expect(parsedBidUrlQueryString).to.have.property('wsName1').and.to.equal('Site 2'); - expect(parsedBidUrlQueryString).to.have.property('wName1').and.to.equal('Page 2'); - expect(parsedBidUrlQueryString).to.have.property('rank1').and.to.equal('123'); - expect(parsedBidUrlQueryString).to.have.property('bfDim1').and.to.equal('200x300'); - expect(parsedBidUrlQueryString).to.have.property('subp1').and.to.equal(''); - - }); - - }); - - describe('placement by id', function () { - - it('should be called with specific parameters for two bids', function () { - - var params = { - bidderCode: 'wideorbit', - bids: [ - { - bidder: 'wideorbit', - params: { - pbId: 1, - pId: 101, - atf: true, - ecpm: 0.8 - }, - placementCode: 'div-gpt-ad-12345-1' - }, - { - bidder: 'wideorbit', - params: { - pbId: 1, - pId: 102, - rank: 123 - }, - placementCode: 'div-gpt-ad-12345-2' - } - ] - }; - - adapter().callBids(params); - - var bidUrl = stubLoadScript.getCall(0).args[0]; - - sinon.assert.calledWith(stubLoadScript, bidUrl); - - var parsedBidUrl = urlParse(bidUrl); - var parsedBidUrlQueryString = querystringify.parse(parsedBidUrl.query); - - expect(parsedBidUrl.hostname).to.equal('p1.atemda.com') - expect(parsedBidUrl.pathname).to.equal('/JSAdservingMP.ashx') - expect(parsedBidUrlQueryString).to.have.property('pc').and.to.equal('2'); - expect(parsedBidUrlQueryString).to.have.property('pbId').and.to.equal('1'); - expect(parsedBidUrlQueryString).to.have.property('jsv').and.to.equal('1.0'); - expect(parsedBidUrlQueryString).to.have.property('tsv').and.to.equal('1.0'); - expect(parsedBidUrlQueryString).to.have.property('cts').to.have.length.above(0); - expect(parsedBidUrlQueryString).to.have.property('arp').and.to.equal('0'); - expect(parsedBidUrlQueryString).to.have.property('fl').and.to.equal('0'); - expect(parsedBidUrlQueryString).to.have.property('jscb').and.to.equal('window.$$PREBID_GLOBAL$$.handleWideOrbitCallback'); - expect(parsedBidUrlQueryString).to.have.property('mpp').and.to.equal('0'); - expect(parsedBidUrlQueryString).to.have.property('cb').to.have.length.above(0); - expect(parsedBidUrlQueryString).to.have.property('hb').and.to.equal('1'); - expect(parsedBidUrlQueryString).to.have.property('url').and.to.be.empty; - - expect(parsedBidUrlQueryString).to.have.property('gid0').and.to.equal('div-gpt-ad-12345-1'); - expect(parsedBidUrlQueryString).to.have.property('rpos0').and.to.equal('1001'); - expect(parsedBidUrlQueryString).to.have.property('ecpm0').and.to.equal('0.8'); - - expect(parsedBidUrlQueryString).to.have.property('gid1').and.to.equal('div-gpt-ad-12345-2'); - expect(parsedBidUrlQueryString).to.have.property('rpos1').and.to.equal('0'); - expect(parsedBidUrlQueryString).to.have.property('ecpm1').and.to.equal(''); - - expect(parsedBidUrlQueryString).to.have.property('pId0').and.to.equal('101'); - expect(parsedBidUrlQueryString).to.have.property('rank0').and.to.equal('0'); - - expect(parsedBidUrlQueryString).to.have.property('pId1').and.to.equal('102'); - expect(parsedBidUrlQueryString).to.have.property('rank1').and.to.equal('123'); - - }); - - }); - - }); - - // describe('handling of the callback response', function () { - // - // var placements = [ - // { - // ExtPlacementId: 'div-gpt-ad-12345-1', - // Type: 'DirectHTML', - // Bid: 1.3, - // Width: 50, - // Height: 100, - // Source: '
The AD 1 itself...
', - // TrackingCodes: [ - // 'https://www.admeta.com/1.gif' - // ] - // }, - // { - // ExtPlacementId: 'div-gpt-ad-12345-2', - // Type: 'DirectHTML', - // Bid: 1.5, - // Width: 100, - // Height: 200, - // Source: '
The AD 2 itself...
', - // TrackingCodes: [ - // 'http://www.admeta.com/2a.gif', - // '' - // ] - // }, - // { - // ExtPlacementId: 'div-gpt-ad-12345-3', - // Type: 'Other', - // Bid: 1.7, - // Width: 150, - // Height: 250, - // Source: '
The AD 3 itself...
', - // TrackingCodes: [ - // 'http://www.admeta.com/3.gif' - // ] - // } - // ]; - // - // it('callback function should exist', function () { - // expect($$PREBID_GLOBAL$$.handleWideOrbitCallback).to.exist.and.to.be.a('function'); - // }); - // - // it('bidmanager.addBidResponse should be called thrice with correct arguments', function () { - // - // var stubAddBidResponse = sinon.stub(bidmanager, 'addBidResponse'); - // - // var params = { - // bidderCode: 'wideorbit', - // bids: [ - // { - // bidder: 'wideorbit', - // params: { - // pbId: 1, - // pId: 101 - // }, - // placementCode: 'div-gpt-ad-12345-1' - // }, - // { - // bidder: 'wideorbit', - // params: { - // pbId: 1, - // site: 'Site 1', - // page: 'Page 1', - // width: 100, - // height: 200, - // subPublisher: 'Sub Publisher 1' - // }, - // placementCode: 'div-gpt-ad-12345-2' - // }, - // { - // bidder: 'wideorbit', - // params: { - // pbId: 1, - // pId: 102 - // }, - // placementCode: 'div-gpt-ad-12345-3' - // }, - // ] - // }; - // - // var response = { - // UserMatchings: [ - // { - // Type: 'redirect', - // Url: 'http%3A%2F%2Fwww.admeta.com%2F1.gif' - // } - // ], - // Placements: placements - // }; - // - // adapter().callBids(params); - // $$PREBID_GLOBAL$$.handleWideOrbitCallback(response); - // - // var bidPlacementCode1 = stubAddBidResponse.getCall(0).args[0]; - // var bidObject1 = stubAddBidResponse.getCall(0).args[1]; - // var bidPlacementCode2 = stubAddBidResponse.getCall(1).args[0]; - // var bidObject2 = stubAddBidResponse.getCall(1).args[1]; - // var bidPlacementCode3 = stubAddBidResponse.getCall(2).args[0]; - // var bidObject3 = stubAddBidResponse.getCall(2).args[1]; - // - // expect(bidPlacementCode1).to.equal('div-gpt-ad-12345-1'); - // expect(bidObject1.cpm).to.equal(1.3); - // expect(bidObject1.ad).to.equal('
The AD 1 itself...
'); - // expect(bidObject1.width).to.equal(50); - // expect(bidObject1.height).to.equal(100); - // expect(bidObject1.getStatusCode()).to.equal(1); - // expect(bidObject1.bidderCode).to.equal('wideorbit'); - // - // expect(bidPlacementCode2).to.equal('div-gpt-ad-12345-2'); - // expect(bidObject2.cpm).to.equal(1.50); - // expect(bidObject2.ad).to.equal('
The AD 2 itself...
'); - // expect(bidObject2.width).to.equal(100); - // expect(bidObject2.height).to.equal(200); - // expect(bidObject2.getStatusCode()).to.equal(1); - // expect(bidObject2.bidderCode).to.equal('wideorbit'); - // - // expect(bidPlacementCode3).to.equal('div-gpt-ad-12345-3'); - // expect(bidObject3.getStatusCode()).to.equal(2); - // expect(bidObject3.bidderCode).to.equal('wideorbit'); - // - // sinon.assert.calledWith(stubAddBidResponse, bidPlacementCode1, bidObject1); - // sinon.assert.calledWith(stubAddBidResponse, bidPlacementCode2, bidObject2); - // sinon.assert.calledWith(stubAddBidResponse, bidPlacementCode3, bidObject3); - // - // sinon.assert.calledThrice(stubAddBidResponse); - // - // stubAddBidResponse.restore(); - // - // }); - // - // it('should append an image to the head when type is set to redirect', function () { - // - // var stubAddBidResponse = sinon.stub(bidmanager, 'addBidResponse'); - // - // var response = { - // UserMatchings: [ - // { - // Type: 'redirect', - // Url: 'http%3A%2F%2Fwww.admeta.com%2F1.gif' - // } - // ], - // Placements: placements - // }; - // - // $$PREBID_GLOBAL$$.handleWideOrbitCallback(response); - // - // var imgElement = document.querySelectorAll("head img")[0]; - // - // expect(imgElement).to.exist; - // expect(imgElement.src).to.equal('http://www.admeta.com/1.gif'); - // - // stubAddBidResponse.restore(); - // }); - // - // it('should append an iframe to the head when type is set to iframe', function () { - // - // var stubAddBidResponse = sinon.stub(bidmanager, 'addBidResponse'); - // - // var response = { - // UserMatchings: [ - // { - // Type: 'iframe', - // Url: 'http%3A%2F%2Fwww.admeta.com%2F1.ashx' - // } - // ], - // Placements: placements - // }; - // - // $$PREBID_GLOBAL$$.handleWideOrbitCallback(response); - // - // var iframeElement = document.querySelectorAll("head iframe")[0]; - // - // expect(iframeElement).to.exist; - // expect(iframeElement.src).to.equal('http://www.admeta.com/1.ashx'); - // - // stubAddBidResponse.restore(); - // - // }); - // - // it('should append an script to the head when type is set to js', function () { - // - // var stubAddBidResponse = sinon.stub(bidmanager, 'addBidResponse'); - // - // var response = { - // UserMatchings: [ - // { - // Type: 'js', - // Url: 'http%3A%2F%2Fwww.admeta.com%2F1.js' - // } - // ], - // Placements: placements - // }; - // - // $$PREBID_GLOBAL$$.handleWideOrbitCallback(response); - // - // var scriptElement = document.querySelectorAll("head script")[0]; - // - // expect(scriptElement).to.exist; - // expect(scriptElement.src).to.equal('http://www.admeta.com/1.js'); - // - // stubAddBidResponse.restore(); - // }); - // - // it('should do nothing when type is set to unrecognized type', function () { - // - // var stubAddBidResponse = sinon.stub(bidmanager, 'addBidResponse'); - // - // var response = { - // UserMatchings: [ - // { - // Type: 'unrecognized', - // Url: 'http%3A%2F%2Fwww.admeta.com%2F1.js' - // } - // ], - // Placements: placements - // }; - // - // $$PREBID_GLOBAL$$.handleWideOrbitCallback(response); - // - // stubAddBidResponse.restore(); - // }); - // - // }); - -}); diff --git a/test/spec/aliasBidder_spec.js b/test/spec/aliasBidder_spec.js index 883576e5546..61a654dcb90 100644 --- a/test/spec/aliasBidder_spec.js +++ b/test/spec/aliasBidder_spec.js @@ -7,7 +7,6 @@ describe('Publisher API _ Alias Bidder', function () { var prebid = require('../../src/prebid'); before(function () { - var topSlotCode = '/19968336/header-bid-tag1'; var topSlotSizes = [[728, 90], [970, 90]]; var adUnit = { @@ -31,12 +30,8 @@ describe('Publisher API _ Alias Bidder', function () { }); describe('set Alias Bidder', function () { - it('should have both of target bidder and alias bidder', function () { - $$PREBID_GLOBAL$$.aliasBidder('appnexus', 'bRealTime1'); - }); }); - }); diff --git a/test/spec/api_spec.js b/test/spec/api_spec.js index 4fde6965975..b3e2e0fc666 100755 --- a/test/spec/api_spec.js +++ b/test/spec/api_spec.js @@ -5,11 +5,18 @@ describe('Publisher API', function () { // var assert = chai.assert; describe('api of command queue', function () { - it('should have a global variable $$PREBID_GLOBAL$$', function () { assert.isObject($$PREBID_GLOBAL$$); }); + it('should have a global variable $$PREBID_GLOBAL$$.cmd as an array', function () { + assert.isArray($$PREBID_GLOBAL$$.cmd); + }); + + it('should have $$PREBID_GLOBAL$$.cmd.push function', function () { + assert.isFunction($$PREBID_GLOBAL$$.cmd.push); + }); + it('should have a global variable $$PREBID_GLOBAL$$.que as an array', function () { assert.isArray($$PREBID_GLOBAL$$.que); }); @@ -20,7 +27,6 @@ describe('Publisher API', function () { }); describe('has function', function () { - it('should have function $$PREBID_GLOBAL$$.getAdserverTargeting', function () { assert.isFunction($$PREBID_GLOBAL$$.getAdserverTargeting); }); @@ -76,7 +82,5 @@ describe('Publisher API', function () { it('should have function $$PREBID_GLOBAL$$.getAllWinningBids', function () { assert.isFunction($$PREBID_GLOBAL$$.getAllWinningBids); }); - }); - }); diff --git a/test/spec/bidmanager_spec.js b/test/spec/bidmanager_spec.js index 602f0beacfc..d47d207c4d5 100644 --- a/test/spec/bidmanager_spec.js +++ b/test/spec/bidmanager_spec.js @@ -1,34 +1,32 @@ -var assert = require("assert"); +var assert = require('assert'); /* use this method to test individual files instead of the whole prebid.js project */ -//TODO refactor to use the spec files +// TODO refactor to use the spec files var utils = require('../../src/utils'); var bidmanager = require('../../src/bidmanager'); var bidfactory = require('../../src/bidfactory'); var fixtures = require('../fixtures/fixtures'); describe('replaceTokenInString', function () { - it('should replace all given tokens in a String', function () { var tokensToReplace = { 'foo': 'bar', 'zap': 'quux' }; - var output = utils.replaceTokenInString("hello %FOO%, I am %ZAP%", tokensToReplace, "%"); - assert.equal(output, "hello bar, I am quux"); + var output = utils.replaceTokenInString('hello %FOO%, I am %ZAP%', tokensToReplace, '%'); + assert.equal(output, 'hello bar, I am quux'); }); it('should ignore tokens it does not see', function () { - var output = utils.replaceTokenInString("hello %FOO%", {}, "%"); + var output = utils.replaceTokenInString('hello %FOO%', {}, '%'); - assert.equal(output, "hello %FOO%"); + assert.equal(output, 'hello %FOO%'); }); }); describe('bidmanager.js', function () { - describe('getKeyValueTargetingPairs', function () { var bid = {}; var bidPriceCpm = 5.578; @@ -57,19 +55,17 @@ describe('bidmanager.js', function () { }; bid.bidderCode = bidderCode; bid.adId = adId; - }); it('No bidder level configuration defined - default', function () { var expected = { - "hb_bidder": bidderCode, - "hb_adid": adId, - "hb_pb": bidPbMg, - "hb_size": size + 'hb_bidder': bidderCode, + 'hb_adid': adId, + 'hb_pb': bidPbMg, + 'hb_size': size }; var response = bidmanager.getKeyValueTargetingPairs(bidderCode, bid); assert.deepEqual(response, expected); - }); it('Custom configuration for all bidders', function () { @@ -78,26 +74,25 @@ describe('bidmanager.js', function () { standard: { adserverTargeting: [ { - key: "hb_bidder", + key: 'hb_bidder', val: function (bidResponse) { return bidResponse.bidderCode; } }, { - key: "hb_adid", + key: 'hb_adid', val: function (bidResponse) { return bidResponse.adId; } }, { - key: "hb_pb", + key: 'hb_pb', val: function (bidResponse) { - //change default here + // change default here return bidResponse.pbHg; } }, { - key: "hb_size", + key: 'hb_size', val: function (bidResponse) { return bidResponse.size; - } } ] @@ -106,14 +101,13 @@ describe('bidmanager.js', function () { }; var expected = { - "hb_bidder": bidderCode, - "hb_adid": adId, - "hb_pb": bidPbHg, - "hb_size": size + 'hb_bidder': bidderCode, + 'hb_adid': adId, + 'hb_pb': bidPbHg, + 'hb_size': size }; var response = bidmanager.getKeyValueTargetingPairs(bidderCode, bid); assert.deepEqual(response, expected); - }); it('Custom configuration for one bidder', function () { @@ -122,26 +116,25 @@ describe('bidmanager.js', function () { appnexus: { adserverTargeting: [ { - key: "hb_bidder", + key: 'hb_bidder', val: function (bidResponse) { return bidResponse.bidderCode; } }, { - key: "hb_adid", + key: 'hb_adid', val: function (bidResponse) { return bidResponse.adId; } }, { - key: "hb_pb", + key: 'hb_pb', val: function (bidResponse) { - //change default here + // change default here return bidResponse.pbHg; } }, { - key: "hb_size", + key: 'hb_size', val: function (bidResponse) { return bidResponse.size; - } } ] @@ -150,14 +143,13 @@ describe('bidmanager.js', function () { }; var expected = { - "hb_bidder": bidderCode, - "hb_adid": adId, - "hb_pb": bidPbHg, - "hb_size": size + 'hb_bidder': bidderCode, + 'hb_adid': adId, + 'hb_pb': bidPbHg, + 'hb_size': size }; var response = bidmanager.getKeyValueTargetingPairs(bidderCode, bid); assert.deepEqual(response, expected); - }); it('Custom configuration for one bidder - not matched', function () { @@ -166,26 +158,25 @@ describe('bidmanager.js', function () { nonExistentBidder: { adserverTargeting: [ { - key: "hb_bidder", + key: 'hb_bidder', val: function (bidResponse) { return bidResponse.bidderCode; } }, { - key: "hb_adid", + key: 'hb_adid', val: function (bidResponse) { return bidResponse.adId; } }, { - key: "hb_pb", + key: 'hb_pb', val: function (bidResponse) { - //change default here + // change default here return bidResponse.pbHg; } }, { - key: "hb_size", + key: 'hb_size', val: function (bidResponse) { return bidResponse.size; - } } ] @@ -194,14 +185,13 @@ describe('bidmanager.js', function () { }; var expected = { - "hb_bidder": bidderCode, - "hb_adid": adId, - "hb_pb": bidPbMg, - "hb_size": size + 'hb_bidder': bidderCode, + 'hb_adid': adId, + 'hb_pb': bidPbMg, + 'hb_size': size }; var response = bidmanager.getKeyValueTargetingPairs(bidderCode, bid); assert.deepEqual(response, expected); - }); it('Custom bidCpmAdjustment for one bidder and inherit standard', function () { @@ -215,19 +205,19 @@ describe('bidmanager.js', function () { standard: { adserverTargeting: [ { - key: "hb_bidder", + key: 'hb_bidder', val: function (bidResponse) { return bidResponse.bidderCode; } }, { - key: "hb_adid", + key: 'hb_adid', val: function (bidResponse) { return bidResponse.adId; } }, { - key: "hb_pb", + key: 'hb_pb', val: function (bidResponse) { - //change default here + // change default here return 10.00; } } @@ -236,10 +226,9 @@ describe('bidmanager.js', function () { } }; - var expected = { "hb_bidder": bidderCode, "hb_adid": adId, "hb_pb": 10.0 }; + var expected = { 'hb_bidder': bidderCode, 'hb_adid': adId, 'hb_pb': 10.0 }; var response = bidmanager.getKeyValueTargetingPairs(bidderCode, bid); assert.deepEqual(response, expected); - }); it('Custom bidCpmAdjustment AND custom configuration for one bidder and inherit standard settings', function () { @@ -251,19 +240,19 @@ describe('bidmanager.js', function () { }, adserverTargeting: [ { - key: "hb_bidder", + key: 'hb_bidder', val: function (bidResponse) { return bidResponse.bidderCode; } }, { - key: "hb_adid", + key: 'hb_adid', val: function (bidResponse) { return bidResponse.adId; } }, { - key: "hb_pb", + key: 'hb_pb', val: function (bidResponse) { - //change default here + // change default here return 15.00; } } @@ -272,27 +261,26 @@ describe('bidmanager.js', function () { standard: { adserverTargeting: [ { - key: "hb_bidder", + key: 'hb_bidder', val: function (bidResponse) { return bidResponse.bidderCode; } }, { - key: "hb_adid", + key: 'hb_adid', val: function (bidResponse) { return bidResponse.adId; } }, { - key: "hb_pb", + key: 'hb_pb', val: function (bidResponse) { - //change default here + // change default here return 10.00; }, }, { - key: "hb_size", + key: 'hb_size', val: function (bidResponse) { return bidResponse.size; - } } ] @@ -301,14 +289,13 @@ describe('bidmanager.js', function () { }; var expected = { - "hb_bidder": bidderCode, - "hb_adid": adId, - "hb_pb": 15.0, - "hb_size": "300x250" + 'hb_bidder': bidderCode, + 'hb_adid': adId, + 'hb_pb': 15.0, + 'hb_size': '300x250' }; var response = bidmanager.getKeyValueTargetingPairs(bidderCode, bid); assert.deepEqual(response, expected); - }); it('alwaysUseBid=true, sendStandardTargeting=false, and inherit custom', function () { @@ -319,17 +306,17 @@ describe('bidmanager.js', function () { sendStandardTargeting: false, adserverTargeting: [ { - key: "hb_bidder", + key: 'hb_bidder', val: function (bidResponse) { return bidResponse.bidderCode; } }, { - key: "hb_adid", + key: 'hb_adid', val: function (bidResponse) { return bidResponse.adId; } }, { - key: "hb_pb", + key: 'hb_pb', val: function (bidResponse) { return bidResponse.pbHg; } @@ -339,10 +326,10 @@ describe('bidmanager.js', function () { }; var expected = { - "hb_bidder": bidderCode, - "hb_adid": adId, - "hb_pb": 5.57, - "hb_size": "300x250" + 'hb_bidder': bidderCode, + 'hb_adid': adId, + 'hb_pb': 5.57, + 'hb_size': '300x250' }; var response = bidmanager.getKeyValueTargetingPairs(bidderCode, bid); assert.deepEqual(response, expected); @@ -350,32 +337,31 @@ describe('bidmanager.js', function () { assert.equal(bid.sendStandardTargeting, false); }); - it('suppressEmptyKeys=true' , function() { + it('suppressEmptyKeys=true', function() { $$PREBID_GLOBAL$$.bidderSettings = { standard: { suppressEmptyKeys: true, adserverTargeting: [ { - key: "aKeyWithAValue", + key: 'aKeyWithAValue', val: 42 }, { - key: "aKeyWithAnEmptyValue", - val: "" + key: 'aKeyWithAnEmptyValue', + val: '' } ] } }; var expected = { - "aKeyWithAValue": 42 + 'aKeyWithAValue': 42 }; var response = bidmanager.getKeyValueTargetingPairs(bidderCode, bid); assert.deepEqual(response, expected); }); - }); describe('adjustBids', () => { @@ -385,7 +371,7 @@ describe('bidmanager.js', function () { fixtures.getBidResponses()[5] ); - assert.equal(bid.cpm, .5); + assert.equal(bid.cpm, 0.5); $$PREBID_GLOBAL$$.bidderSettings = { @@ -410,12 +396,12 @@ describe('bidmanager.js', function () { // negative bid.adUnitCode = 'negative'; bidmanager.adjustBids(bid) - assert.equal(bid.cpm, .5); + assert.equal(bid.cpm, 0.5); // positive bid.adUnitCode = 'normal'; bidmanager.adjustBids(bid) - assert.equal(bid.cpm, .25); + assert.equal(bid.cpm, 0.25); // zero bid.adUnitCode = 'zero'; @@ -424,7 +410,6 @@ describe('bidmanager.js', function () { // reset bidderSettings so we don't mess up further tests $$PREBID_GLOBAL$$.bidderSettings = {}; - }); }); @@ -474,7 +459,7 @@ describe('bidmanager.js', function () { fixtures.getBidResponses()[0] ); - bid.dealId = "test deal"; + bid.dealId = 'test deal'; bidmanager.addBidResponse(bid.adUnitCode, bid); const addedBid = $$PREBID_GLOBAL$$._bidsReceived.pop(); assert.equal(addedBid.adserverTargeting[`hb_deal`], bid.dealId, 'dealId placed in adserverTargeting'); @@ -490,13 +475,85 @@ describe('bidmanager.js', function () { fixtures.getBidResponses()[3] ); - bidmanager.addBidResponse(bid1.adUnitCode, Object.assign({},bid1)); - bidmanager.addBidResponse(bid2.adUnitCode, Object.assign({},bid2)); + bidmanager.addBidResponse(bid1.adUnitCode, Object.assign({}, bid1)); + bidmanager.addBidResponse(bid2.adUnitCode, Object.assign({}, bid2)); const addedBid2 = $$PREBID_GLOBAL$$._bidsReceived.pop(); assert.equal(addedBid2.adId, bid2.adId); const addedBid1 = $$PREBID_GLOBAL$$._bidsReceived.pop(); assert.equal(addedBid1.adId, bid1.adId); }); + + it('should not add native bids that do not have required assets', () => { + sinon.stub(utils, 'getBidRequest', () => ({ + bidder: 'appnexusAst', + nativeParams: { + title: {'required': true}, + }, + mediaType: 'native', + })); + + const bid = Object.assign({}, + bidfactory.createBid(1), + { + bidderCode: 'appnexusAst', + mediaType: 'native', + native: {title: undefined} + } + ); + + const bidsRecCount = $$PREBID_GLOBAL$$._bidsReceived.length; + bidmanager.addBidResponse('adUnit-code', bid); + assert.equal(bidsRecCount, $$PREBID_GLOBAL$$._bidsReceived.length); + + utils.getBidRequest.restore(); + }); + + it('should add native bids that do have required assets', () => { + sinon.stub(utils, 'getBidRequest', () => ({ + bidder: 'appnexusAst', + nativeParams: { + title: {'required': true}, + }, + mediaType: 'native', + })); + + const bid = Object.assign({}, + bidfactory.createBid(1), + { + bidderCode: 'appnexusAst', + mediaType: 'native', + native: {title: 'foo'} + } + ); + + const bidsRecCount = $$PREBID_GLOBAL$$._bidsReceived.length; + bidmanager.addBidResponse('adUnit-code', bid); + assert.equal(bidsRecCount + 1, $$PREBID_GLOBAL$$._bidsReceived.length); + + utils.getBidRequest.restore(); + }); + + it('installs publisher-defined renderers on bids', () => { + sinon.stub(utils, 'getBidderRequest', () => ({ + bids: [{ + renderer: { + url: 'renderer.js', + render: (bid) => bid + } + }] + })); + + const bid = Object.assign({}, bidfactory.createBid(1), { + bidderCode: 'appnexusAst', + mediaType: 'video-outstream', + }); + + bidmanager.addBidResponse('adUnit-code', bid); + const addedBid = $$PREBID_GLOBAL$$._bidsReceived.pop(); + assert.equal(addedBid.renderer.url, 'renderer.js'); + + utils.getBidderRequest.restore(); + }); }); }); diff --git a/test/spec/cookie_spec.js b/test/spec/cookie_spec.js index 1cf3fa80b02..9c7dcaebf3a 100644 --- a/test/spec/cookie_spec.js +++ b/test/spec/cookie_spec.js @@ -3,7 +3,6 @@ import { expect } from 'chai'; var utils = require('../../src/utils'); describe('cookie.queueSync', () => { - let insertCookieSyncIframeStub = sinon.stub(utils, 'insertCookieSyncIframe'); let insertPixelStub = sinon.stub(utils, 'insertPixel'); @@ -13,7 +12,7 @@ describe('cookie.queueSync', () => { }); it('queues and fires a pixel URL', () => { - cookie.queueSync({'bidder' : 'testBidder', 'url': 'http://url.com'}); + cookie.queueSync({'bidder': 'testBidder', 'url': 'http://url.com'}); cookie.syncCookies(); expect(insertPixelStub.getCall(0).args[0]).to.exist.and.to.equal('http://url.com'); }); @@ -29,5 +28,4 @@ describe('cookie.queueSync', () => { expect(insertCookieSyncIframeStub.callCount).to.equal(0); expect(insertPixelStub.callCount).to.equal(0); }); - }); diff --git a/test/spec/core/adapterManager_spec.js b/test/spec/core/adapterManager_spec.js new file mode 100644 index 00000000000..55557f1e342 --- /dev/null +++ b/test/spec/core/adapterManager_spec.js @@ -0,0 +1,56 @@ +import { expect } from 'chai'; +import AdapterManager from 'src/adaptermanager'; +import { getAdUnits } from 'test/fixtures/fixtures'; +import CONSTANTS from 'src/constants.json'; + +const CONFIG = { + enabled: true, + endpoint: CONSTANTS.S2S.DEFAULT_ENDPOINT, + timeout: 1000, + maxBids: 1, + adapter: 'prebidServer', + bidders: ['appnexus'] +}; +var prebidServerAdapterMock = { + bidder: 'prebidServer', + callBids: sinon.stub(), + setConfig: sinon.stub(), + queueSync: sinon.stub() +}; + +describe('adapterManager tests', () => { + describe('S2S tests', () => { + beforeEach(() => { + AdapterManager.setS2SConfig(CONFIG); + AdapterManager.bidderRegistry['prebidServer'] = prebidServerAdapterMock; + prebidServerAdapterMock.callBids.reset(); + }); + + it('invokes callBids on the S2S adapter', () => { + AdapterManager.callBids({adUnits: getAdUnits()}); + sinon.assert.calledOnce(prebidServerAdapterMock.callBids); + }); + + it('invokes callBids with only s2s bids', () => { + const adUnits = getAdUnits(); + // adUnit without appnexus bidder + adUnits.push({ + 'code': '123', + 'sizes': [300, 250], + 'bids': [ + { + 'bidder': 'adequant', + 'params': { + 'publisher_id': '1234567', + 'bidfloor': 0.01 + } + } + ] + }); + AdapterManager.callBids({adUnits: adUnits}); + const requestObj = prebidServerAdapterMock.callBids.firstCall.args[0]; + expect(requestObj.ad_units.length).to.equal(2); + sinon.assert.calledOnce(prebidServerAdapterMock.callBids); + }); + }); // end s2s tests +}); diff --git a/test/spec/cpmBucketManager_spec.js b/test/spec/cpmBucketManager_spec.js index 8b9d71c7c55..1590a647417 100644 --- a/test/spec/cpmBucketManager_spec.js +++ b/test/spec/cpmBucketManager_spec.js @@ -3,10 +3,9 @@ import {getPriceBucketString, isValidePriceConfig} from 'src/cpmBucketManager'; let cpmFixtures = require('test/fixtures/cpmInputsOutputs.json'); describe('cpmBucketManager', () => { - it('getPriceBucketString function generates the correct price strings', () => { let input = cpmFixtures.cpmInputs; - for(let i = 0; i < input.length; i++){ + for (let i = 0; i < input.length; i++) { let output = getPriceBucketString(input[i]); let jsonOutput = JSON.stringify(output); expect(jsonOutput).to.deep.equal(JSON.stringify(cpmFixtures.priceStringOutputs[i])); @@ -16,19 +15,19 @@ describe('cpmBucketManager', () => { it('gets the correct custom bucket strings', () => { let cpm = 16.50908; let customConfig = { - "buckets" : [{ - "precision" : 4, - "min" : 0, - "max" : 3, - "increment" : 0.01, - }, - { - "precision" : 4, - "min" : 3, - "max" : 18, - "increment" : 0.05, - "cap" : true - } + 'buckets': [{ + 'precision': 4, + 'min': 0, + 'max': 3, + 'increment': 0.01, + }, + { + 'precision': 4, + 'min': 3, + 'max': 18, + 'increment': 0.05, + 'cap': true + } ] }; let expected = '{"low":"5.00","med":"16.50","high":"16.50","auto":"16.50","dense":"16.50","custom":"16.5000"}'; @@ -38,21 +37,20 @@ describe('cpmBucketManager', () => { it('checks whether custom config is valid', () => { let badConfig = { - "buckets" : [{ - "min" : 0, - "max" : 3, - "increment" : 0.01, - }, - { - //missing min prop - "max" : 18, - "increment" : 0.05, - "cap" : true - } + 'buckets': [{ + 'min': 0, + 'max': 3, + 'increment': 0.01, + }, + { + // missing min prop + 'max': 18, + 'increment': 0.05, + 'cap': true + } ] }; expect(isValidePriceConfig(badConfig)).to.be.false; }); - }); diff --git a/test/spec/e2e/common/globals.js b/test/spec/e2e/common/globals.js index 153670f15f7..3e781d5fa21 100644 --- a/test/spec/e2e/common/globals.js +++ b/test/spec/e2e/common/globals.js @@ -1,9 +1,9 @@ var HtmlReporter = require('nightwatch-html-reporter'); var reporter = new HtmlReporter({ - openBrowser: true, - reportsDirectory: __dirname + '/reports', - themeName: 'cover', + openBrowser: true, + reportsDirectory: __dirname + '/reports', + themeName: 'cover', }); module.exports = { - reporter: reporter.fn + reporter: reporter.fn }; diff --git a/test/spec/e2e/common/utils.js b/test/spec/e2e/common/utils.js index c745610f564..2c9fee68eda 100644 --- a/test/spec/e2e/common/utils.js +++ b/test/spec/e2e/common/utils.js @@ -1,10 +1,10 @@ module.exports = { - findIframeInDiv : function(divid) { + findIframeInDiv: function(divid) { var div = document.getElementById(divid); var iframes = div.getElementsByTagName('iframe'); console.log(iframes.length); try { - if(iframes.length === 1 && iframes[0].contentWindow.document.body.innerHTML === "") { + if (iframes.length === 1 && iframes[0].contentWindow.document.body.innerHTML === '') { return false; } else { return true; diff --git a/test/spec/e2e/custom-assertions/first.js b/test/spec/e2e/custom-assertions/first.js index 296dc86d352..e393e8c15a0 100644 --- a/test/spec/e2e/custom-assertions/first.js +++ b/test/spec/e2e/custom-assertions/first.js @@ -43,7 +43,7 @@ exports.assertion = function(expected, msg) { this.command = function(callback) { var _this = this; var execcallback = function(result) { - //console.log(_this); + // console.log(_this); console.log('**********'); console.log(result); console.log(callback.toString()); @@ -52,14 +52,13 @@ exports.assertion = function(expected, msg) { } }; - this.api.execute(function(){ - //cusotm logic + this.api.execute(function() { + // cusotm logic return 'hello'; }, [], execcallback); - //var result = {'value':'hello'}; + // var result = {'value':'hello'}; return this; }; - }; diff --git a/test/spec/e2e/custom-reporter/pbjs-html-reporter.js b/test/spec/e2e/custom-reporter/pbjs-html-reporter.js index b5cb55b3ecc..bcd5eab1e21 100644 --- a/test/spec/e2e/custom-reporter/pbjs-html-reporter.js +++ b/test/spec/e2e/custom-reporter/pbjs-html-reporter.js @@ -3,8 +3,7 @@ var mkpath = require('mkpath'); var path = require('path'); var ejs = require('ejs'); -module.exports = new (function() { - +module.exports = new function() { var tmpl = __dirname + '/junit.xml.ejs'; var tmplData; var globalResults; @@ -50,10 +49,10 @@ module.exports = new (function() { adaptAssertions(module); var rendered = ejs.render(data, { - module : module, - moduleName : moduleName, - systemerr : globalResults.errmessages.join('\n'), - }); + module: module, + moduleName: moduleName, + systemerr: globalResults.errmessages.join('\n'), + }); if (pathParts.length) { output_folder = path.join(output_folder, pathParts.join(path.sep)); @@ -70,9 +69,9 @@ module.exports = new (function() { function stackTraceFilter(parts) { var stack = parts.reduce(function(list, line) { if (contains(line, [ - 'node_modules', - '(node.js:', - '(events.js:' + 'node_modules', + '(node.js:', + '(events.js:' ])) { return list; } @@ -85,7 +84,7 @@ module.exports = new (function() { } function contains(str, text) { - if( Object.prototype.toString.call( text ) === '[object Array]' ) { + if (Object.prototype.toString.call(text) === '[object Array]') { for (var i = 0; i < text.length; i++) { if (contains(str, text[i])) { return true; @@ -96,7 +95,7 @@ module.exports = new (function() { } this.write = function(results, options, callback) { - options.filename_prefix = process.env.__NIGHTWATCH_ENV+'_'; + options.filename_prefix = process.env.__NIGHTWATCH_ENV + '_'; globalResults = results; var keys = Object.keys(results.modules); @@ -112,5 +111,4 @@ module.exports = new (function() { }); }); }; - -})(); +}(); diff --git a/test/spec/e2e/testcase1/dom-group/allbidders_dom_spec.js b/test/spec/e2e/testcase1/dom-group/allbidders_dom_spec.js index f4fa7e754cf..5803ad5ceb3 100644 --- a/test/spec/e2e/testcase1/dom-group/allbidders_dom_spec.js +++ b/test/spec/e2e/testcase1/dom-group/allbidders_dom_spec.js @@ -1,8 +1,8 @@ -//var verify = require('verify'); +// var verify = require('verify'); var util = require('../../common/utils.js'); module.exports = { - 'adequant ad rendering' : function (browser) { + 'adequant ad rendering': function (browser) { browser .url('http://an.localhost:9999/test/spec/e2e/gpt-examples/all_bidders_instant_load.html') .waitForElementVisible('body', 5000) @@ -11,115 +11,115 @@ module.exports = { this.verify.equal(result.value, true, 'adequant ad not rendered'); }); }, - 'adform ad rendering' : function (browser) { + 'adform ad rendering': function (browser) { browser .execute(util.findIframeInDiv, ['div-2'], function(result) { this.verify.equal(result.value, true, 'adform ad not rendered'); }); }, - 'aol ad rendering' : function (browser) { + 'aol ad rendering': function (browser) { browser .execute(util.findIframeInDiv, ['div-3'], function(result) { this.verify.equal(result.value, true, 'aol ad not rendered'); }); }, - 'appnexus ad rendering' : function (browser) { + 'appnexus ad rendering': function (browser) { browser .execute(util.findIframeInDiv, ['div-4'], function(result) { this.verify.equal(result.value, true, 'appnexus ad not rendered'); }); }, - 'indexExchange ad rendering' : function (browser) { + 'indexExchange ad rendering': function (browser) { browser .execute(util.findIframeInDiv, ['div-5'], function(result) { this.verify.equal(result.value, true, 'indexExchange ad not rendered'); }); }, - 'openx ad rendering' : function (browser) { + 'openx ad rendering': function (browser) { browser .execute(util.findIframeInDiv, ['div-6'], function(result) { this.verify.equal(result.value, true, 'openx ad not rendered'); }); }, - 'pubmatic ad rendering' : function (browser) { + 'pubmatic ad rendering': function (browser) { browser .execute(util.findIframeInDiv, ['div-7'], function(result) { this.verify.equal(result.value, true, 'pubmatic ad not rendered'); }); }, - 'pulsepoint ad rendering' : function (browser) { + 'pulsepoint ad rendering': function (browser) { browser .execute(util.findIframeInDiv, ['div-8'], function(result) { this.verify.equal(result.value, true, 'pulsepoint ad not rendered'); }); }, - 'rubicon ad rendering' : function (browser) { + 'rubicon ad rendering': function (browser) { browser .execute(util.findIframeInDiv, ['div-9'], function(result) { this.verify.equal(result.value, true, 'rubicon ad not rendered'); }); }, - 'sonobi ad rendering' : function (browser) { + 'sonobi ad rendering': function (browser) { browser .execute(util.findIframeInDiv, ['div-10'], function(result) { this.verify.equal(result.value, true, 'sonobi ad not rendered'); }); }, - 'sovrn ad rendering' : function (browser) { + 'sovrn ad rendering': function (browser) { browser .execute(util.findIframeInDiv, ['div-11'], function(result) { this.verify.equal(result.value, true, 'sovrn ad not rendered'); }); }, - 'springserve ad rendering' : function (browser) { + 'springserve ad rendering': function (browser) { browser .execute(util.findIframeInDiv, ['div-12'], function(result) { this.verify.equal(result.value, true, 'springserve ad not rendered'); }); }, - 'triplelift ad rendering' : function (browser) { + 'triplelift ad rendering': function (browser) { browser .execute(util.findIframeInDiv, ['div-13'], function(result) { this.verify.equal(result.value, true, 'triplelift ad not rendered'); }); }, - 'yieldbot ad rendering' : function (browser) { + 'yieldbot ad rendering': function (browser) { browser .execute(util.findIframeInDiv, ['div-14'], function(result) { this.verify.equal(result.value, true, 'yieldbot ad not rendered'); }); }, - 'nginad ad rendering' : function (browser) { + 'nginad ad rendering': function (browser) { browser .execute(util.findIframeInDiv, ['div-15'], function(result) { this.verify.equal(result.value, true, 'nginad ad not rendered'); }); }, - 'brightcom ad rendering' : function (browser) { + 'brightcom ad rendering': function (browser) { browser .execute(util.findIframeInDiv, ['div-16'], function(result) { this.verify.equal(result.value, true, 'brightcom ad not rendered'); }); }, - 'sekindo ad rendering' : function (browser) { + 'sekindo ad rendering': function (browser) { browser .execute(util.findIframeInDiv, ['div-17'], function(result) { this.verify.equal(result.value, true, 'sekindo ad not rendered'); }); }, - 'kruxlink ad rendering' : function (browser) { + 'kruxlink ad rendering': function (browser) { browser .execute(util.findIframeInDiv, ['div-18'], function(result) { this.verify.equal(result.value, true, 'kruxlink ad not rendered'); }); }, - 'AdMedia ad rendering' : function (browser) { + 'AdMedia ad rendering': function (browser) { browser .execute(util.findIframeInDiv, ['div-19'], function(result) { this.verify.equal(result.value, true, 'AdMedia ad not rendered'); }); }, - after : function(browser) { + after: function(browser) { browser.end(); } }; diff --git a/test/spec/e2e/testcase1/dom-group/dom_spec.js b/test/spec/e2e/testcase1/dom-group/dom_spec.js index 3ed5252bf26..a58030c32b7 100644 --- a/test/spec/e2e/testcase1/dom-group/dom_spec.js +++ b/test/spec/e2e/testcase1/dom-group/dom_spec.js @@ -1,14 +1,13 @@ -//var assert = require('assert'); +// var assert = require('assert'); module.exports = { - 'Test rendering ad div-2' : function (browser) { - + 'Test rendering ad div-2': function (browser) { var checkAdRendering2 = function() { var div = document.getElementById('div-2'); var iframes = div.getElementsByTagName('iframe'); try { - if(iframes.length == 1 && iframes[0].contentWindow.document.body.innerHTML == "") { + if (iframes.length == 1 && iframes[0].contentWindow.document.body.innerHTML == '') { return false; } else { return true; @@ -26,13 +25,12 @@ module.exports = { this.assert.equal(result.value, true, 'Ad of div-2 not rendered'); }); }, - 'Test rendering ad div-1' : function (browser) { - + 'Test rendering ad div-1': function (browser) { var checkAdRendering = function() { var div = document.getElementById('div-1'); var iframes = div.getElementsByTagName('iframe'); try { - if(iframes.length == 1 && iframes[0].contentWindow.document.body.innerHTML == "") { + if (iframes.length == 1 && iframes[0].contentWindow.document.body.innerHTML == '') { return false; } else { return true; @@ -47,7 +45,7 @@ module.exports = { this.assert.equal(result.value, true, 'Ad of div-1 not rendered'); }); }, - after : function(browser) { + after: function(browser) { browser.end(); } }; diff --git a/test/spec/e2e/testcase1/pbjsapi-group/adservertargeting_spec.js b/test/spec/e2e/testcase1/pbjsapi-group/adservertargeting_spec.js index 67d0306d438..796707641cd 100644 --- a/test/spec/e2e/testcase1/pbjsapi-group/adservertargeting_spec.js +++ b/test/spec/e2e/testcase1/pbjsapi-group/adservertargeting_spec.js @@ -2,31 +2,30 @@ var assert = require('assert'); var utils = require('util'); module.exports = { - 'AdserverTargeting Test Case 1' : function (browser) { + 'AdserverTargeting Test Case 1': function (browser) { browser .url('http://localhost:9999/test/spec/e2e/gpt-examples/gpt_default.html') .waitForElementVisible('body', 3000) .pause(3000) - .execute(function(){ - - if(typeof window.pbjs.bidderSettings == "undefined") { + .execute(function() { + if (typeof window.pbjs.bidderSettings === 'undefined') { var pbjsBidderSettingsObject = [ - "hb_bidder", - "hb_adid", - "hb_pb", - "hb_size" + 'hb_bidder', + 'hb_adid', + 'hb_pb', + 'hb_size' ]; } else { var pbjsBidderSettings = window.pbjs.bidderSettings; var pbjsBidderSettingsObject = {}; Object.keys(pbjsBidderSettings).forEach(function (prop) { - //if(prop == 'standard') return; + // if(prop == 'standard') return; var value = pbjsBidderSettings[prop]; - var bs = value.adserverTargeting.map(function(item){ + var bs = value.adserverTargeting.map(function(item) { return item.key; }); - pbjsBidderSettings.standard.adserverTargeting.map(function(value){ - if(bs.indexOf(value.key) == -1 ) { + pbjsBidderSettings.standard.adserverTargeting.map(function(value) { + if (bs.indexOf(value.key) == -1) { bs.push(value.key) } }); @@ -36,18 +35,18 @@ module.exports = { var adserverTargetingObject = {}; var adserverTargeting = window.pbjs.getAdserverTargeting(); - Object.keys(adserverTargeting).forEach(function(value){ - if(Object.keys(adserverTargeting[value]).length == 0) return; + Object.keys(adserverTargeting).forEach(function(value) { + if (Object.keys(adserverTargeting[value]).length == 0) return; adserverTargetingObject[adserverTargeting[value].hb_bidder] = Object.keys(adserverTargeting[value]) }); return [pbjsBidderSettingsObject, adserverTargetingObject]; }, [], function(result) { Object.keys(result.value[1]).forEach(function(key) { - if(utils.isArray(result.value[0])) { + if (utils.isArray(result.value[0])) { assert.deepEqual(result.value[0].sort(), result.value[1][key].sort()); } else { - if(result.value[0].hasOwnProperty(key)) { + if (result.value[0].hasOwnProperty(key)) { var obj1 = result.value[0][key].sort(); } else { var obj1 = result.value[0]['standard'].sort(); @@ -57,7 +56,7 @@ module.exports = { }); }); }, - after : function(browser) { + after: function(browser) { browser.end(); } }; diff --git a/test/spec/e2e/testcase1/pbjsapi-group/getbidresponses_spec.js b/test/spec/e2e/testcase1/pbjsapi-group/getbidresponses_spec.js index ed260f7f33f..c7921709c0f 100644 --- a/test/spec/e2e/testcase1/pbjsapi-group/getbidresponses_spec.js +++ b/test/spec/e2e/testcase1/pbjsapi-group/getbidresponses_spec.js @@ -1,34 +1,34 @@ -//var assert = require('assert'); +// var assert = require('assert'); var assert = require('chai').assert; var utils = require('util'); module.exports = { - 'bidReceived not empty' : function(browser) { + 'bidReceived not empty': function(browser) { browser .url('http://localhost:9999/test/spec/e2e/gpt-examples/gpt_default.html') .waitForElementVisible('body', 3000) .pause(5000) .execute(function() { - return window.pbjs._bidsReceived.length; + return window.pbjs._bidsReceived.length; }, [], function(result) { - //browser.assert.first(false, 'Bid response empty'); + // browser.assert.first(false, 'Bid response empty'); assert.isOk(result.value, 'Bid response empty'); }); }, - 'check keys' : function(browser) { + 'check keys': function(browser) { browser .execute(function() { return window.pbjs._bidsReceived; }, [], function(result) { - //minimum expected keys in bid received - var expected = ["bidderCode", "width", "height", "adId", "cpm", "requestId", "bidder", "adUnitCode", "timeToRespond"]; - Object.keys(result.value).forEach(function(key){ + // minimum expected keys in bid received + var expected = ['bidderCode', 'width', 'height', 'adId', 'cpm', 'requestId', 'bidder', 'adUnitCode', 'timeToRespond']; + Object.keys(result.value).forEach(function(key) { var compare = Object.keys(result.value[key]); assert.includeMembers(compare, expected, 'include members'); }); }); }, - after : function(browser) { + after: function(browser) { browser.end(); } }; diff --git a/test/spec/integration/faker/fixtures.js b/test/spec/integration/faker/fixtures.js index df625a57093..643b531ad42 100644 --- a/test/spec/integration/faker/fixtures.js +++ b/test/spec/integration/faker/fixtures.js @@ -39,4 +39,4 @@ export function makeRequest(overrides = {}) { }, overrides); } -export function randomFive() { return faker.random.number({ min: 10000, max: 99999 }); } \ No newline at end of file +export function randomFive() { return faker.random.number({ min: 10000, max: 99999 }); } diff --git a/test/spec/loaders/adapterLoader_spec.js b/test/spec/loaders/adapterLoader_spec.js deleted file mode 100644 index e3b07a15330..00000000000 --- a/test/spec/loaders/adapterLoader_spec.js +++ /dev/null @@ -1,74 +0,0 @@ -'use strict'; - -const proxyquire = require('proxyquire'); -const allAdapters = require('../../fixtures/allAdapters'); -const expect = require('chai').expect; -require('../../../loaders/adapterLoader'); - -const defaultAdapters = ["aardvark","adblade","adbutler","adequant","adform","admedia","aol","appnexus","appnexusAst","getintent","hiromedia","indexExchange","kruxlink","komoona","openx","piximedia","pubmatic","pulsepoint","rubicon","sonobi","sovrn","springserve","thoughtleadr","triplelift","twenga","yieldbot","nginad","brightcom","wideorbit","jcm","underdogmedia","memeglobal","centro","roxot",{"appnexus":{"alias":"brealtime"}},{"appnexus":{"alias":"pagescience"}},{"appnexus":{"alias":"defymedia"}},{"appnexusAst":{"supportedMediaTypes":["video"]}}]; - -const input = `/** INSERT ADAPTERS - DO NOT EDIT OR REMOVE */ - /** END INSERT ADAPTERS */`; - -const delimiter = '/*!ADAPTER REGISTER DELIMITER*/'; - -const getAdaptersWithDelimiter = () => { - return delimiter +'var AardvarkAdapter = require(\'./adapters/aardvark.js\');\n ' + - 'exports.registerBidAdapter(new AardvarkAdapter(), \'aardvark\');\n' + - delimiter + - 'var AolAdapter = require(\'./adapters/aol.js\');\n ' + - 'exports.registerBidAdapter(new AolAdapter(), \'aol\');\n' + - delimiter + - 'var AppnexusAdapter = require(\'./adapters/appnexus.js\');\n ' + - 'exports.registerBidAdapter(new AppnexusAdapter(), \'appnexus\');\n' + - delimiter + - 'var RubiconAdapter = require(\'./adapters/rubicon.js\');\n ' + - 'exports.registerBidAdapter(new RubiconAdapter(), \'rubicon\');\n' + - delimiter + - 'exports.aliasBidAdapter(\'appnexus\',\'pagescience\');\n' + - delimiter + - 'exports.videoAdapters = ["appnexusAst"];'; -}; - -describe('adapterLoader.js', () => { - it('should replace with the default set of adapters', () => { - const getAdapterStub = () => [ - 'aardvark', - 'aol', - 'appnexus', - 'rubicon', - {"appnexus":{"alias":"pagescience"}}, - {"appnexusAst":{"supportedMediaTypes":["video"]}} - ]; - const loader = proxyquire('../../../loaders/adapterLoader', {'./getAdapters' : getAdapterStub}); - let output = loader(input); - expect(output).to.equal(getAdaptersWithDelimiter()); - }); - - it('should return custom adapter list if file exists', () => { - const customAdapter = [{customAdapterName :{srcPath: '/somepath/customAdapterName.js'}}]; - const getAdapterStub = () => customAdapter; - const loader = proxyquire('../../../loaders/adapterLoader', {'fs': {existsSync : ()=> true }, './getAdapters' : getAdapterStub}); - let output = loader(input); - const expected = delimiter + - 'let customAdapterName = require(\'/somepath/customAdapterName.js\');\n ' + - 'exports.registerBidAdapter(new customAdapterName, \'customAdapterName\');\n' + - delimiter + - 'exports.videoAdapters = [];'; - expect(output).to.equal(expected); - }); - - it('should ignore custom adapters that that do not exist', () => { - const customAdapter = ['appnexus', {customAdapterName :{srcPath: '/somepath/customAdapterName.js'}}]; - const getAdapterStub = () => customAdapter; - const loader = proxyquire('../../../loaders/adapterLoader', {'fs': {existsSync : ()=> false }, './getAdapters' : getAdapterStub}); - let output = loader(input); - const expected = delimiter + - 'var AppnexusAdapter = require(\'./adapters/appnexus.js\');\n ' + - 'exports.registerBidAdapter(new AppnexusAdapter(), \'appnexus\');\n' + - delimiter + - 'exports.videoAdapters = [];'; - expect(output).to.equal(expected); - }); - -}); diff --git a/test/spec/loaders/delimiterLoader_spec.js b/test/spec/loaders/delimiterLoader_spec.js new file mode 100644 index 00000000000..bb2071e3a03 --- /dev/null +++ b/test/spec/loaders/delimiterLoader_spec.js @@ -0,0 +1,31 @@ +import {expect} from 'chai'; + +describe('delimiterLoader', () => { + it('should wrap content for bidAdapter files', () => { + let loader = require('loaders/delimiterLoader'); + let options = {file: 'aolBidAdapter.js'}; + let adapterContent = 'test-adapter-content'; + + let expectedContent = '/*!ADAPTER BEGIN aol*/' + adapterContent + '/*!ADAPTER END aol*/'; + + expect(loader(adapterContent, options)).to.equal(expectedContent); + }); + + it('should wrap content for analyticsAdapter files', () => { + let loader = require('loaders/delimiterLoader'); + let options = {file: 'testbidderAnalyticsAdapter.js'}; + let adapterContent = 'test-adapter-content'; + + let expectedContent = '/*!ANALYTICS ADAPTER BEGIN testbidder*/' + adapterContent + '/*!ANALYTICS ADAPTER END testbidder*/'; + + expect(loader(adapterContent, options)).to.equal(expectedContent); + }); + + it('should not wrap content for unrecognized files', () => { + let loader = require('loaders/delimiterLoader'); + let options = {file: 'dfpAdServerVideo.js'}; + let adapterContent = 'test-adapter-content'; + + expect(loader(adapterContent, options)).to.equal(adapterContent); + }); +}); diff --git a/test/spec/loaders/getAdapters_spec.js b/test/spec/loaders/getAdapters_spec.js deleted file mode 100644 index 3cb6a4db74a..00000000000 --- a/test/spec/loaders/getAdapters_spec.js +++ /dev/null @@ -1,93 +0,0 @@ -'use strict'; - -const mockfs = require('mock-fs'); -const proxyquire = require('proxyquire'); -const expect = require('chai').expect; - -require('../../../loaders/getAdapters'); - -describe('loaders/getAdapters', () => { - - let defaultAdapters; - let customAdapters; - const defaultAdaptersFile = 'adapters.json'; - const adaptersArg = 'adapters'; - - beforeEach(() => { - defaultAdapters = [ 'adapter 1', 'adapter 2', 'adapter 3' ]; - customAdapters = [ 'adapter 1' ]; - }); - - afterEach(() => { - mockfs.restore(); - }); - - describe('when custom adapter list is defined', () => { - - describe('and exists', () => { - - it('should return custom adapter list', () => { - mockfs({ - 'adapters.json': JSON.stringify(defaultAdapters), - 'custom-adapters.json': JSON.stringify(customAdapters) - }); - const getAdapters = proxyquire('../../../loaders/getAdapters', { - yargs: { argv: { adapters: 'custom-adapters.json' } } - }); - expect(getAdapters(defaultAdaptersFile, adaptersArg)).to.deep.equal(customAdapters); - }); - - }); - - describe('and does not exist', () => { - - it('should return default adapter list and show warning', () => { - let log; - const consoleLog = console.log.bind(console); - console.log = (message) => { - log = message; - }; - mockfs({ - 'adapters.json': JSON.stringify(defaultAdapters) - }); - const getAdapters = proxyquire('../../../loaders/getAdapters', { - yargs: { argv: { adapters: 'non-existent-adapters.json' } } - }); - expect(getAdapters(defaultAdaptersFile, adaptersArg)).to.deep.equal(defaultAdapters); - expect(log).to.match(/non-existent-adapters.json/); - console.log = consoleLog; - }); - - }); - - }); - - describe('when custom adapter list is not defined', () => { - - it('should return default adapter list', () => { - mockfs({ - 'adapters.json': JSON.stringify(defaultAdapters) - }); - const getAdapters = proxyquire('../../../loaders/getAdapters', { - yargs: { argv: {} } - }); - expect(getAdapters(defaultAdaptersFile, adaptersArg)).to.deep.equal(defaultAdapters); - }); - - }); - - describe('when default adapter list cannot be found', () => { - - it('should return empty array', () => { - mockfs({ - 'adapters.json': mockfs.file({ mode: 0x000 }) - }); - const getAdapters = proxyquire('../../../loaders/getAdapters', { - yargs: { argv: {} } - }); - expect(getAdapters(defaultAdaptersFile, adaptersArg)).to.deep.equal([]); - }); - - }); - -}); diff --git a/test/spec/adapters/aardvark_spec.js b/test/spec/modules/aardvarkBidAdapter_spec.js similarity index 72% rename from test/spec/adapters/aardvark_spec.js rename to test/spec/modules/aardvarkBidAdapter_spec.js index 4d94d5c7cc3..9ea97dcccc5 100644 --- a/test/spec/adapters/aardvark_spec.js +++ b/test/spec/modules/aardvarkBidAdapter_spec.js @@ -1,98 +1,95 @@ describe('aardvark adapter tests', function () { const expect = require('chai').expect; - const adapter = require('src/adapters/aardvark'); + const adapter = require('modules/aardvarkBidAdapter'); const bidmanager = require('src/bidmanager'); const adloader = require('src/adloader'); - const constants = require('src/constants.json'); + const constants = require('src/constants.json'); var aardvark, - sandbox, - bidsRequestedOriginal; + sandbox, + bidsRequestedOriginal; const bidderRequest = { - bidderCode: 'aardvark', - bids: [ - { - bidId: 'bidId1', - bidder: 'aardvark', - placementCode: 'foo', - sizes: [[728, 90]], - rtkid: 1, - params: { - ai: 'AH5S', - sc: 'BirH' - } - }, - { - bidId: 'bidId2', - bidder: 'aardvark', - placementCode: 'bar', - sizes: [[300, 600]], - rtkid: 1, - params: { - ai: 'AH5S', - sc: '661h' - } - } - ] + bidderCode: 'aardvark', + bids: [ + { + bidId: 'bidId1', + bidder: 'aardvark', + placementCode: 'foo', + sizes: [[728, 90]], + rtkid: 1, + params: { + ai: 'AH5S', + sc: 'BirH' + } }, - - bidderRequestCustomHost = { - bidderCode: 'aardvark', - bids: [ - { - bidId: 'bidId1', - bidder: 'aardvark', - placementCode: 'foo', - sizes: [[728, 90]], - rtkid: 1, - params: { - ai: 'AH5S', - sc: 'BirH', - host: 'custom.server.com' - } - }, - { - bidId: 'bidId2', - bidder: 'aardvark', - placementCode: 'bar', - sizes: [[300, 600]], - rtkid: 1, - params: { - ai: 'AH5S', - sc: '661h', - host: 'custom.server.com' - } - } - ] + { + bidId: 'bidId2', + bidder: 'aardvark', + placementCode: 'bar', + sizes: [[300, 600]], + rtkid: 1, + params: { + ai: 'AH5S', + sc: '661h' + } + } + ] + }, + + bidderRequestCustomHost = { + bidderCode: 'aardvark', + bids: [ + { + bidId: 'bidId1', + bidder: 'aardvark', + placementCode: 'foo', + sizes: [[728, 90]], + rtkid: 1, + params: { + ai: 'AH5S', + sc: 'BirH', + host: 'custom.server.com' + } }, - - - - // respond - bidderResponse = [ - { - "adm": "
", - "cpm": 0.39440, - "ex": "", - "height": "90", - "id": "BirH", - "nurl": "", - "width": "728", - "cid": "bidId1" - }, - { - "adm": "
", - "cpm": 0.03485, - "ex": "", - "height": "600", - "id": "661h", - "nurl": "", - "width": "300", - "cid": "bidId2" + { + bidId: 'bidId2', + bidder: 'aardvark', + placementCode: 'bar', + sizes: [[300, 600]], + rtkid: 1, + params: { + ai: 'AH5S', + sc: '661h', + host: 'custom.server.com' } - ]; - + } + ] + }, + + // respond + bidderResponse = [ + { + 'adm': '
', + 'cpm': 0.39440, + 'ex': '', + 'height': '90', + 'id': 'BirH', + 'nurl': '', + 'width': '728', + 'cid': 'bidId1' + }, + { + 'adm': '
', + 'cpm': 0.03485, + 'ex': '', + 'height': '600', + 'id': '661h', + 'nurl': '', + 'width': '300', + 'cid': 'bidId2' + } + ]; beforeEach(() => { aardvark = new adapter(); @@ -101,14 +98,12 @@ describe('aardvark adapter tests', function () { $$PREBID_GLOBAL$$._bidsRequested = []; }); - afterEach(() => { sandbox.restore(); $$PREBID_GLOBAL$$._bidsRequested = bidsRequestedOriginal; }); - describe('callBids', () => { beforeEach(() => { sandbox.stub(adloader, 'loadScript'); @@ -121,7 +116,6 @@ describe('aardvark adapter tests', function () { }); }); - describe('callBids with custom host', () => { beforeEach(() => { sandbox.stub(adloader, 'loadScript'); @@ -134,15 +128,12 @@ describe('aardvark adapter tests', function () { }); }); - describe('aardvarkResponse', () => { it('should exist and be a function', () => { expect($$PREBID_GLOBAL$$.aardvarkResponse).to.exist.and.to.be.a('function'); }); }); - - describe('add empty bids if no bid returned', () => { let firstBid; let secondBid; @@ -185,10 +176,8 @@ describe('aardvark adapter tests', function () { expect(firstBid).to.have.property('bidderCode', 'aardvark'); expect(secondBid).to.have.property('bidderCode', 'aardvark'); }); - }); - describe('add bids to the manager', () => { let firstBid; let secondBid; @@ -248,9 +237,4 @@ describe('aardvark adapter tests', function () { expect(secondBid).to.have.property('height', 600); }); }); - - - - }); - diff --git a/test/spec/adapters/adblade_spec.js b/test/spec/modules/adbladeBidAdapter_spec.js similarity index 90% rename from test/spec/adapters/adblade_spec.js rename to test/spec/modules/adbladeBidAdapter_spec.js index 729917c626d..c66bfe70d3f 100644 --- a/test/spec/adapters/adblade_spec.js +++ b/test/spec/modules/adbladeBidAdapter_spec.js @@ -1,5 +1,5 @@ import {expect} from 'chai'; -import Adapter from '../../../src/adapters/adblade'; +import Adapter from '../../../modules/adbladeBidAdapter'; import bidManager from '../../../src/bidmanager'; import adLoader from '../../../src/adloader'; @@ -84,7 +84,6 @@ describe('adblade adapter', () => { }); describe('callBids', () => { - beforeEach(() => { sandbox.stub(adLoader, 'loadScript'); adapter.callBids(bidderRequest); @@ -96,18 +95,15 @@ describe('adblade adapter', () => { expect(adLoader.loadScript.firstCall.args[0]).to.include('adblade.com'); expect(adLoader.loadScript.firstCall.args[0]).to.include('prebidjs'); }); - }); describe('adbladeResponse', () => { - it('should exist and be a function', () => { expect(pbjs.adbladeResponse).to.exist.and.to.be.a('function'); }); }); describe('add bids to the manager', () => { - let firstBid; beforeEach(() => { @@ -117,25 +113,25 @@ describe('adblade adapter', () => { // respond let bidderReponse = { - "cur": "USD", - "id": "03a9404f-7b39-4d04-b50b-6459b9aa3ffa", - "seatbid": [ + 'cur': 'USD', + 'id': '03a9404f-7b39-4d04-b50b-6459b9aa3ffa', + 'seatbid': [ { - "seat": "1", - "bid": [ + 'seat': '1', + 'bid': [ { - "nurl": "http://example.com", - "crid": "20063", - "adomain": [ - "www.adblade.com" + 'nurl': 'http://example.com', + 'crid': '20063', + 'adomain': [ + 'www.adblade.com' ], - "price": 3, - "w": 728, - "h": 90, - "id": "1", - "adm": "
", - "impid": "bidId1", - "cid": "99" + 'price': 3, + 'w': 728, + 'h': 90, + 'id': '1', + 'adm': '
', + 'impid': 'bidId1', + 'cid': '99' } ] } @@ -175,7 +171,6 @@ describe('adblade adapter', () => { }); describe('add empty bids if no bid returned', () => { - let firstBid; beforeEach(() => { @@ -207,6 +202,5 @@ describe('adblade adapter', () => { it('should add the bidder code to the bid object', () => { expect(firstBid).to.have.property('bidderCode', 'adblade'); }); - }); }); diff --git a/test/spec/modules/adbundBidAdapter_spec.js b/test/spec/modules/adbundBidAdapter_spec.js new file mode 100644 index 00000000000..da9b2e2e9b9 --- /dev/null +++ b/test/spec/modules/adbundBidAdapter_spec.js @@ -0,0 +1,94 @@ +import { expect } from 'chai'; +import Adapter from '../../../modules/adbundBidAdapter'; +import bidManager from 'src/bidmanager'; +import CONSTANTS from 'src/constants.json'; + +describe('adbund adapter tests', function () { + let sandbox; + let adapter; + let server; + + const request = { + bidderCode: 'adbund', + bids: [{ + bidder: 'adbund', + params: { + sid: '110238', + bidfloor: 0.036 + }, + placementCode: 'adbund', + sizes: [[300, 250]], + bidId: 'adbund_bidId', + bidderRequestId: 'adbund_bidderRequestId', + requestId: 'adbund_requestId' + }] + }; + + const response = { + bidderCode: 'adbund', + cpm: 1.06, + height: 250, + width: 300 + }; + + beforeEach(() => { + sandbox = sinon.sandbox.create(); + }); + + afterEach(() => { + sandbox.restore(); + }); + + describe('adbund callBids validation', () => { + beforeEach(() => { + adapter = new Adapter(); + }); + + afterEach(() => { + }); + + it('Valid bid-request', () => { + let bidderRequest; + + sandbox.stub(adapter, 'callBids'); + adapter.callBids(request); + + bidderRequest = adapter.callBids.getCall(0).args[0]; + + expect(bidderRequest).to.have.property('bids') + .that.is.an('array') + .with.lengthOf(1); + + expect(bidderRequest).to.have.deep.property('bids[0]') + .to.have.property('bidder', 'adbund'); + + expect(bidderRequest).to.have.deep.property('bids[0]') + .with.property('sizes') + .that.is.an('array') + .with.lengthOf(1) + .that.deep.equals(request.bids[0].sizes); + + expect(bidderRequest).to.have.deep.property('bids[0]') + .with.property('params') + .to.have.property('bidfloor', 0.036); + }); + + it('Valid bid-response', () => { + var bidderResponse; + + sandbox.stub(bidManager, 'addBidResponse'); + adapter.callBids(request); + bidderResponse = bidManager.addBidResponse.getCall(0) || + bidManager.addBidResponse.getCall(1); + + if (bidderResponse && bidderResponse.args && bidderResponse.args[1]) { + bidderResponse = bidderResponse.args[1]; + expect(bidderResponse.getStatusCode()).to.equal(CONSTANTS.STATUS.GOOD); + expect(bidderResponse.bidderCode).to.equal(response.bidderCode); + expect(bidderResponse.width).to.equal(response.width); + expect(bidderResponse.height).to.equal(response.height); + expect(bidderResponse.cpm).to.equal(response.cpm); + } + }); + }); +}); diff --git a/test/spec/modules/adbutlerBidAdapter_spec.js b/test/spec/modules/adbutlerBidAdapter_spec.js new file mode 100644 index 00000000000..ec7073545b2 --- /dev/null +++ b/test/spec/modules/adbutlerBidAdapter_spec.js @@ -0,0 +1,516 @@ +describe('adbutler adapter tests', function () { + var expect = require('chai').expect; + var adapter = require('modules/adbutlerBidAdapter'); + var adLoader = require('src/adloader'); + var bidmanager = require('src/bidmanager'); + + describe('creation of bid url', function () { + var stubLoadScript; + + beforeEach(function () { + stubLoadScript = sinon.stub(adLoader, 'loadScript'); + }); + + afterEach(function () { + stubLoadScript.restore(); + }); + + if (typeof (pbjs._bidsReceived) === 'undefined') { + pbjs._bidsReceived = []; + } + if (typeof (pbjs._bidsRequested) === 'undefined') { + pbjs._bidsRequested = []; + } + if (typeof (pbjs._adsReceived) === 'undefined') { + pbjs._adsReceived = []; + } + + it('should be called', function () { + var params = { + bidderCode: 'adbutler', + bids: [ + { + bidId: '3c9408cdbf2f68', + sizes: [[300, 250]], + bidder: 'adbutler', + params: { + accountID: '167283', + zoneID: '210093' + }, + requestId: '10b327aa396609', + placementCode: '/123456/header-bid-tag-1' + } + + ] + }; + + adapter().callBids(params); + + sinon.assert.called(stubLoadScript); + }); + + it('should populate the keyword', function() { + var params = { + bidderCode: 'adbutler', + bids: [ + { + bidId: '3c9408cdbf2f68', + sizes: [[300, 250]], + bidder: 'adbutler', + params: { + accountID: '167283', + zoneID: '210093', + keyword: 'fish' + }, + requestId: '10b327aa396609', + placementCode: '/123456/header-bid-tag-1' + } + + ] + }; + + adapter().callBids(params); + + var requestURI = stubLoadScript.getCall(0).args[0]; + + expect(requestURI).to.have.string(';kw=fish;'); + }); + + it('should use custom domain string', function() { + var params = { + bidderCode: 'adbutler', + bids: [ + { + bidId: '3c9408cdbf2f68', + sizes: [[300, 250]], + bidder: 'adbutler', + params: { + accountID: '107878', + zoneID: '86133', + domain: 'servedbyadbutler.com.dan.test' + }, + requestId: '10b327aa396609', + placementCode: '/123456/header-bid-tag-1' + } + ] + }; + + adapter().callBids(params); + + var requestURI = stubLoadScript.getCall(0).args[0]; + + expect(requestURI).to.have.string('.dan.test'); + }); + }); + describe('bid responses', function() { + it('should return complete bid response', function() { + var stubAddBidResponse = sinon.stub(bidmanager, 'addBidResponse'); + + var params = { + bidderCode: 'adbutler', + bidder: 'adbutler', + bids: [ + { + bidId: '3c94018cdbf2f68-1', + sizes: [[300, 250]], + bidder: 'adbutler', + params: { + accountID: '167283', + zoneID: '210093', + }, + requestId: '10b327aa396609', + placementCode: '/123456/header-bid-tag-1' + } + + ] + }; + + var response = { + status: 'SUCCESS', + account_id: 167283, + zone_id: 210093, + cpm: 1.5, + width: 300, + height: 250, + place: 0 + }; + + adapter().callBids(params); + + var adUnits = new Array(); + var unit = new Object(); + unit.bids = params.bids; + unit.code = '/123456/header-bid-tag-1'; + unit.sizes = [[300, 250]]; + adUnits.push(unit); + + if (typeof (pbjs._bidsRequested) === 'undefined') { + pbjs._bidsRequested = [params]; + } else { + pbjs._bidsRequested.push(params); + } + + pbjs.adUnits = adUnits; + + pbjs.adbutlerCB(response); + + var bidPlacementCode1 = stubAddBidResponse.getCall(0).args[0]; + var bidObject1 = stubAddBidResponse.getCall(0).args[1]; + + expect(bidPlacementCode1).to.equal('/123456/header-bid-tag-1'); + expect(bidObject1.getStatusCode()).to.equal(1); + expect(bidObject1.bidderCode).to.equal('adbutler'); + expect(bidObject1.cpm).to.equal(1.5); + expect(bidObject1.width).to.equal(300); + expect(bidObject1.height).to.equal(250); + + stubAddBidResponse.restore(); + }); + + it('should return empty bid response', function() { + var stubAddBidResponse = sinon.stub(bidmanager, 'addBidResponse'); + var params = { + bidderCode: 'adbutler', + bids: [ + { + bidId: '3c9408cdbf2f68-2', + sizes: [[300, 250]], + bidder: 'adbutler', + params: { + accountID: '167283', + zoneID: '210085', + }, + requestId: '10b327aa396609', + placementCode: '/123456/header-bid-tag-1' + } + + ] + }; + + var response = { + status: 'NO_ELIGIBLE_ADS', + zone_id: 210085, + width: 728, + height: 90, + place: 0 + }; + + adapter().callBids(params); + + var adUnits = new Array(); + var unit = new Object(); + unit.bids = params.bids; + unit.code = '/123456/header-bid-tag-1'; + unit.sizes = [[300, 250]]; + adUnits.push(unit); + + if (typeof (pbjs._bidsRequested) === 'undefined') { + pbjs._bidsRequested = [params]; + } else { + pbjs._bidsRequested.push(params); + } + + pbjs.adUnits = adUnits; + + pbjs.adbutlerCB(response); + + var bidPlacementCode1 = stubAddBidResponse.getCall(0).args[0]; + var bidObject1 = stubAddBidResponse.getCall(0).args[1]; + + expect(bidPlacementCode1).to.equal('/123456/header-bid-tag-1'); + expect(bidObject1.getStatusCode()).to.equal(2); + expect(bidObject1.bidderCode).to.equal('adbutler'); + + stubAddBidResponse.restore(); + }); + + it('should return empty bid response on incorrect size', function() { + var stubAddBidResponse = sinon.stub(bidmanager, 'addBidResponse'); + var params = { + bidderCode: 'adbutler', + bids: [ + { + bidId: '3c9408cdbf2f68-3', + sizes: [[300, 250]], + bidder: 'adbutler', + params: { + accountID: '167283', + zoneID: '210085', + }, + requestId: '10b327aa396609', + placementCode: '/123456/header-bid-tag-1' + } + + ] + }; + + var response = { + status: 'SUCCESS', + account_id: 167283, + zone_id: 210085, + cpm: 1.5, + width: 728, + height: 90, + place: 0 + }; + + adapter().callBids(params); + + var adUnits = new Array(); + var unit = new Object(); + unit.bids = params.bids; + unit.code = '/123456/header-bid-tag-1'; + unit.sizes = [[300, 250]]; + adUnits.push(unit); + + if (typeof (pbjs._bidsRequested) === 'undefined') { + pbjs._bidsRequested = [params]; + } else { + pbjs._bidsRequested.push(params); + } + + pbjs.adUnits = adUnits; + + pbjs.adbutlerCB(response); + + var bidObject1 = stubAddBidResponse.getCall(0).args[1]; + expect(bidObject1.getStatusCode()).to.equal(2); + + stubAddBidResponse.restore(); + }); + + it('should return empty bid response with CPM too low', function() { + var stubAddBidResponse = sinon.stub(bidmanager, 'addBidResponse'); + var params = { + bidderCode: 'adbutler', + bids: [ + { + bidId: '3c9408cdbf2f68-4', + sizes: [[300, 250]], + bidder: 'adbutler', + params: { + accountID: '167283', + zoneID: '210093', + minCPM: '5.00' + }, + requestId: '10b327aa396609', + placementCode: '/123456/header-bid-tag-1' + } + + ] + }; + + var response = { + status: 'SUCCESS', + account_id: 167283, + zone_id: 210093, + cpm: 1.5, + width: 300, + height: 250, + place: 0 + }; + + adapter().callBids(params); + + var adUnits = new Array(); + var unit = new Object(); + unit.bids = params.bids; + unit.code = '/123456/header-bid-tag-1'; + unit.sizes = [[300, 250]]; + adUnits.push(unit); + + if (typeof (pbjs._bidsRequested) === 'undefined') { + pbjs._bidsRequested = [params]; + } else { + pbjs._bidsRequested.push(params); + } + + pbjs.adUnits = adUnits; + + pbjs.adbutlerCB(response); + + var bidObject1 = stubAddBidResponse.getCall(0).args[1]; + expect(bidObject1.getStatusCode()).to.equal(2); + + stubAddBidResponse.restore(); + }); + + it('should return empty bid response with CPM too high', function() { + var stubAddBidResponse = sinon.stub(bidmanager, 'addBidResponse'); + + var params = { + bidderCode: 'adbutler', + bids: [ + { + bidId: '3c9408cdbf2f68-5', + sizes: [[300, 250]], + bidder: 'adbutler', + params: { + accountID: '167283', + zoneID: '210093', + maxCPM: '1.00' + }, + requestId: '10b327aa396609', + placementCode: '/123456/header-bid-tag-1' + } + + ] + }; + + var response = { + status: 'SUCCESS', + account_id: 167283, + zone_id: 210093, + cpm: 1.5, + width: 300, + height: 250, + place: 0 + }; + + adapter().callBids(params); + + var adUnits = new Array(); + var unit = new Object(); + unit.bids = params.bids; + unit.code = '/123456/header-bid-tag-1'; + unit.sizes = [[300, 250]]; + adUnits.push(unit); + + if (typeof (pbjs._bidsRequested) === 'undefined') { + pbjs._bidsRequested = [params]; + } else { + pbjs._bidsRequested.push(params); + } + + pbjs.adUnits = adUnits; + + pbjs.adbutlerCB(response); + + var bidObject1 = stubAddBidResponse.getCall(0).args[1]; + expect(bidObject1.getStatusCode()).to.equal(2); + + stubAddBidResponse.restore(); + }); + }); + + describe('ad code', function() { + it('should be populated', function() { + var stubAddBidResponse = sinon.stub(bidmanager, 'addBidResponse'); + + var params = { + bidderCode: 'adbutler', + bids: [ + { + bidId: '3c9408cdbf2f68-6', + sizes: [[300, 250]], + bidder: 'adbutler', + params: { + accountID: '167283', + zoneID: '210093' + }, + requestId: '10b327aa396609', + placementCode: '/123456/header-bid-tag-1' + } + + ] + }; + + var response = { + status: 'SUCCESS', + account_id: 167283, + zone_id: 210093, + cpm: 1.5, + width: 300, + height: 250, + place: 0, + ad_code: '' + }; + + adapter().callBids(params); + + var adUnits = new Array(); + var unit = new Object(); + unit.bids = params.bids; + unit.code = '/123456/header-bid-tag-1'; + unit.sizes = [[300, 250]]; + adUnits.push(unit); + + if (typeof (pbjs._bidsRequested) === 'undefined') { + pbjs._bidsRequested = [params]; + } else { + pbjs._bidsRequested.push(params); + } + + pbjs.adUnits = adUnits; + + pbjs.adbutlerCB(response); + + var bidObject1 = stubAddBidResponse.getCall(0).args[1]; + expect(bidObject1.getStatusCode()).to.equal(1); + expect(bidObject1.ad).to.have.length.above(1); + + stubAddBidResponse.restore(); + }); + + it('should contain tracking pixels', function() { + var stubAddBidResponse = sinon.stub(bidmanager, 'addBidResponse'); + + var params = { + bidderCode: 'adbutler', + bids: [ + { + bidId: '3c9408cdbf2f68-7', + sizes: [[300, 250]], + bidder: 'adbutler', + params: { + accountID: '167283', + zoneID: '210093' + }, + requestId: '10b327aa396609', + placementCode: '/123456/header-bid-tag-1' + } + + ] + }; + + var response = { + status: 'SUCCESS', + account_id: 167283, + zone_id: 210093, + cpm: 1.5, + width: 300, + height: 250, + place: 0, + ad_code: '', + tracking_pixels: [ + 'http://tracking.pixel.com/params=info' + ] + }; + + adapter().callBids(params); + + var adUnits = new Array(); + var unit = new Object(); + unit.bids = params.bids; + unit.code = '/123456/header-bid-tag-1'; + unit.sizes = [[300, 250]]; + adUnits.push(unit); + + if (typeof (pbjs._bidsRequested) === 'undefined') { + pbjs._bidsRequested = [params]; + } else { + pbjs._bidsRequested.push(params); + } + + pbjs.adUnits = adUnits; + + pbjs.adbutlerCB(response); + + var bidObject1 = stubAddBidResponse.getCall(0).args[1]; + expect(bidObject1.getStatusCode()).to.equal(1); + expect(bidObject1.ad).to.have.string('http://tracking.pixel.com/params=info'); + + stubAddBidResponse.restore(); + }); + }); +}); diff --git a/test/spec/adapters/adform_spec.js b/test/spec/modules/adformBidAdapter_spec.js similarity index 89% rename from test/spec/adapters/adform_spec.js rename to test/spec/modules/adformBidAdapter_spec.js index 70ad3807259..0d2d1e19b68 100644 --- a/test/spec/adapters/adform_spec.js +++ b/test/spec/modules/adformBidAdapter_spec.js @@ -1,13 +1,11 @@ -// jshint esversion: 6 - import { assert } from 'chai'; import * as utils from '../../../src/utils'; import adLoader from '../../../src/adloader'; import bidManager from '../../../src/bidmanager'; -import adapter from '../../../src/adapters/adform'; +import adapter from '../../../modules/adformBidAdapter'; describe('Adform adapter', () => { - let _adapter, sandbox; + let _adapter, sandbox; describe('request', () => { it('should create callback method on PREBID_GLOBAL', () => { @@ -30,16 +28,16 @@ describe('Adform adapter', () => { assert.equal(_query.callback.split('.')[1], '_adf_callback'); assert.equal(_query.tid, 145); assert.equal(_query.rp, 4); + assert.equal(_query.fd, 1); assert.equal(_query.url, encodeURIComponent('some// there')); }); - it('should correctly form bid items', () => { const _items = parseUrl(adLoader.loadScript.args[0][0]).items; - assert.deepEqual(_items[0], { mid: '1' }); - assert.deepEqual(_items[1], { mid: '2', someVar: 'someValue' }); - assert.deepEqual(_items[2], { mid: '3', pdom: 'home' }); + assert.deepEqual(_items[0], { mid: '1', transactionId: 'transactionId' }); + assert.deepEqual(_items[1], { mid: '2', someVar: 'someValue', transactionId: 'transactionId' }); + assert.deepEqual(_items[2], { mid: '3', pdom: 'home', transactionId: 'transactionId' }); }); }); @@ -61,6 +59,7 @@ describe('Adform adapter', () => { assert.equal(_bidObject.width, 90); assert.equal(_bidObject.height, 90); assert.equal(_bidObject.dealId, 'deal-1'); + assert.equal(_bidObject.transactionId, 'transactionId'); }); it('should correctly form empty bid response object', () => { @@ -112,6 +111,7 @@ describe('Adform adapter', () => { }); beforeEach(() => { + var transactionId = 'transactionId'; _adapter = adapter(); utils.getUniqueIdentifierStr = () => 'callback'; sandbox = sinon.sandbox.create(); @@ -127,7 +127,8 @@ describe('Adform adapter', () => { url: 'some// there' }, adxDomain: 'newdomain', - tid: 45 + tid: 45, + transactionId: transactionId }, { bidId: '123', @@ -137,7 +138,8 @@ describe('Adform adapter', () => { mid: 2, tid: 145, someVar: 'someValue' - } + }, + transactionId: transactionId }, { bidId: 'a1b', @@ -146,9 +148,10 @@ describe('Adform adapter', () => { params: { mid: 3, pdom: 'home' - } + }, + transactionId: transactionId } - ]}); + ]}); }); afterEach(() => { @@ -162,7 +165,7 @@ function parseUrl(url) { return { path: parts.join('/'), items: query - .filter((i) => ! ~i.indexOf('=')) + .filter((i) => !~i.indexOf('=')) .map((i) => fromBase64(i) .split('&') .reduce(toObject, {})), @@ -189,4 +192,4 @@ function toObject(cache, string) { const keyValue = string.split('='); cache[keyValue[0]] = keyValue[1]; return cache; -} \ No newline at end of file +} diff --git a/test/spec/adapters/adkernel_spec.js b/test/spec/modules/adkernelBidAdapter_spec.js similarity index 61% rename from test/spec/adapters/adkernel_spec.js rename to test/spec/modules/adkernelBidAdapter_spec.js index f505a4188f2..87bf3430d5d 100644 --- a/test/spec/adapters/adkernel_spec.js +++ b/test/spec/modules/adkernelBidAdapter_spec.js @@ -1,68 +1,96 @@ import {expect} from 'chai'; -import Adapter from 'src/adapters/adkernel'; +import Adapter from 'modules/adkernelBidAdapter'; import * as ajax from 'src/ajax'; import * as utils from 'src/utils'; import bidmanager from 'src/bidmanager'; import CONSTANTS from 'src/constants.json'; describe('Adkernel adapter', () => { - const bid1_zone1 = { - bidder: 'adkernel', - bidId: 'Bid_01', - params: {zoneId: 1, host: 'rtb.adkernel.com'}, - placementCode: 'ad-unit-1', - sizes: [[300, 250]] - }, bid2_zone2 = { - bidder: 'adkernel', - bidId: 'Bid_02', - params: {zoneId: 2, host: 'rtb.adkernel.com'}, - placementCode: 'ad-unit-2', - sizes: [[728, 90]] - }, bid3_host2 = { - bidder: 'adkernel', - bidId: 'Bid_02', - params: {zoneId: 1, host: 'rtb-private.adkernel.com'}, - placementCode: 'ad-unit-2', - sizes: [[728, 90]] - }, bid_without_zone = { - bidder: 'adkernel', - bidId: 'Bid_W', - params: {host: 'rtb-private.adkernel.com'}, - placementCode: 'ad-unit-1', - sizes: [[728, 90]] - }, bid_without_host = { - bidder: 'adkernel', - bidId: 'Bid_W', - params: {zoneId: 1}, - placementCode: 'ad-unit-1', - sizes: [[728, 90]] - }; + bidder: 'adkernel', + bidId: 'Bid_01', + params: {zoneId: 1, host: 'rtb.adkernel.com'}, + placementCode: 'ad-unit-1', + sizes: [[300, 250]] + }, bid2_zone2 = { + bidder: 'adkernel', + bidId: 'Bid_02', + params: {zoneId: 2, host: 'rtb.adkernel.com'}, + placementCode: 'ad-unit-2', + sizes: [[728, 90]] + }, bid3_host2 = { + bidder: 'adkernel', + bidId: 'Bid_02', + params: {zoneId: 1, host: 'rtb-private.adkernel.com'}, + placementCode: 'ad-unit-2', + sizes: [[728, 90]] + }, bid_without_zone = { + bidder: 'adkernel', + bidId: 'Bid_W', + params: {host: 'rtb-private.adkernel.com'}, + placementCode: 'ad-unit-1', + sizes: [[728, 90]] + }, bid_without_host = { + bidder: 'adkernel', + bidId: 'Bid_W', + params: {zoneId: 1}, + placementCode: 'ad-unit-1', + sizes: [[728, 90]] + }, bid_video = { + bidder: 'adkernel', + bidId: 'Bid_Video', + sizes: [640, 480], + mediaType: 'video', + params: { + zoneId: 1, + host: 'rtb.adkernel.com', + video: { + mimes: ['video/mp4', 'video/webm', 'video/x-flv'] + } + }, + placementCode: 'ad-unit-1' + }; const bidResponse1 = { - 'id': 'bid1', - 'seatbid': [{ - 'bid': [{ - 'id': '1', - 'impid': 'Bid_01', - 'price': 3.01, - 'nurl': 'https://rtb.com/win?i=ZjKoPYSFI3Y_0', - 'adm': '' - }] - }], - 'cur': 'USD' - }, bidResponse2 = { - 'id': 'bid2', - 'seatbid': [{ - 'bid': [{ - 'id': '2', - 'impid': 'Bid_02', - 'price': 1.31, - 'adm': '' - }] - }], - 'cur': 'USD' - }; + id: 'bid1', + seatbid: [{ + bid: [{ + id: '1', + impid: 'Bid_01', + price: 3.01, + nurl: 'https://rtb.com/win?i=ZjKoPYSFI3Y_0', + adm: '' + }] + }], + cur: 'USD' + }, bidResponse2 = { + id: 'bid2', + seatbid: [{ + bid: [{ + id: '2', + impid: 'Bid_02', + price: 1.31, + adm: '' + }] + }], + cur: 'USD' + }, videoBidResponse = { + id: '47ce4badcf7482', + seatbid: [{ + bid: [{ + id: 'sZSYq5zYMxo_0', + impid: 'Bid_Video', + price: 0.00145, + adid: '158801', + nurl: 'https://rtb.com/win?i=sZSYq5zYMxo_0&f=nurl', + cid: '16855', + crid: '158801', + w: 600, + h: 400 + }] + }], + cur: 'USD' + }; let adapter, sandbox, @@ -85,7 +113,7 @@ describe('Adkernel adapter', () => { }); } - describe('input parameters validation', ()=> { + describe('input parameters validation', () => { let spy; beforeEach(() => { @@ -114,7 +142,7 @@ describe('Adkernel adapter', () => { }); }); - describe('request building', () => { + describe('banner request building', () => { let bidRequest; beforeEach(() => { @@ -124,7 +152,7 @@ describe('Adkernel adapter', () => { hostname: 'example.com', host: 'example.com', pathname: '/index.html', - href : 'http://example.com/index.html' + href: 'http://example.com/index.html' }; }); @@ -151,7 +179,6 @@ describe('Adkernel adapter', () => { }); it('should have tagid', () => { - // console.warn(bidRequest.imp[0]); expect(bidRequest.imp[0]).to.have.property('tagid', 'ad-unit-1'); }); @@ -160,16 +187,46 @@ describe('Adkernel adapter', () => { expect(bidRequest.site).to.have.property('page', 'http://example.com/index.html'); }); - it('should fill device with caller macro', ()=> { + it('should fill device with caller macro', () => { expect(bidRequest).to.have.property('device'); expect(bidRequest.device).to.have.property('ip', 'caller'); expect(bidRequest.device).to.have.property('ua', 'caller'); }) + }); + describe('video request building', () => { + let bidRequest; + + beforeEach(() => { + sandbox.stub(utils, 'getTopWindowLocation', () => { + return { + protocol: 'https:', + hostname: 'example.com', + host: 'example.com', + pathname: '/index.html', + href: 'http://example.com/index.html' + }; + }); + ajaxStub.onCall(0).callsArgWith(1, JSON.stringify(videoBidResponse)); + doRequest([bid_video]); + bidRequest = JSON.parse(decodeURIComponent(ajaxStub.getCall(0).args[2].r)); + }); + + it('should have video object', () => { + expect(bidRequest.imp[0]).to.have.property('video'); + }); + + it('should have h/w', () => { + expect(bidRequest.imp[0].video).to.have.property('w', 640); + expect(bidRequest.imp[0].video).to.have.property('h', 480); + }); + + it('should have tagid', () => { + expect(bidRequest.imp[0]).to.have.property('tagid', 'ad-unit-1'); + }); }); describe('requests routing', () => { - it('should issue a request for each network', () => { ajaxStub.onFirstCall().callsArgWith(1, '') .onSecondCall().callsArgWith(1, ''); @@ -196,7 +253,6 @@ describe('Adkernel adapter', () => { }); describe('responses processing', () => { - beforeEach(() => { sandbox.stub(bidmanager, 'addBidResponse'); }); @@ -214,6 +270,20 @@ describe('Adkernel adapter', () => { expect(bidResponse.height).to.equal(250); }); + it('should return fully-initialized video bid-response', () => { + ajaxStub.onCall(0).callsArgWith(1, JSON.stringify(videoBidResponse)); + doRequest([bid_video]); + let bidResponse = bidmanager.addBidResponse.firstCall.args[1]; + expect(bidmanager.addBidResponse.firstCall.args[0]).to.equal('ad-unit-1'); + expect(bidResponse.getStatusCode()).to.equal(CONSTANTS.STATUS.GOOD); + expect(bidResponse.mediaType).to.equal('video'); + expect(bidResponse.bidderCode).to.equal('adkernel'); + expect(bidResponse.cpm).to.equal(0.00145); + expect(bidResponse.vastUrl).to.equal('https://rtb.com/win?i=sZSYq5zYMxo_0&f=nurl'); + expect(bidResponse.width).to.equal(600); + expect(bidResponse.height).to.equal(400); + }); + it('should map responses to proper ad units', () => { ajaxStub.onCall(0).callsArgWith(1, JSON.stringify(bidResponse1)); ajaxStub.onCall(1).callsArgWith(1, JSON.stringify(bidResponse2)); @@ -238,28 +308,33 @@ describe('Adkernel adapter', () => { expect(bidmanager.addBidResponse.secondCall.args[0]).to.equal('ad-unit-2'); }); - it('should add nurl as pixel', () => { + it('should add nurl as pixel for banner response', () => { sandbox.spy(utils, 'createTrackPixelHtml'); ajaxStub.onCall(0).callsArgWith(1, JSON.stringify(bidResponse1)); doRequest([bid1_zone1]); - expect(bidmanager.addBidResponse.firstCall.args[1].getStatusCode()).to.equal(CONSTANTS.STATUS.GOOD); expect(utils.createTrackPixelHtml.calledOnce); - let result = pbjs.getBidResponsesForAdUnitCode(bid1_zone1.placementCode); + expect(bidmanager.addBidResponse.firstCall.args[1].getStatusCode()).to.equal(CONSTANTS.STATUS.GOOD); let expectedNurl = bidResponse1.seatbid[0].bid[0].nurl + '&px=1'; - expect(result.bids[0].ad).to.include(expectedNurl); + expect(bidmanager.addBidResponse.firstCall.args[1].ad).to.include(expectedNurl); }); it('should perform usersync for each unique host/zone combination', () => { ajaxStub.callsArgWith(1, ''); - const expectedSyncUrls = ['http://rtb.adkernel.com/user-sync?zone=1', 'http://rtb.adkernel.com/user-sync?zone=2', - 'http://rtb-private.adkernel.com/user-sync?zone=1']; - sandbox.spy(utils, 'createInvisibleIframe'); + const expectedSyncUrls = ['//sync.adkernel.com/user-sync?zone=1&r=%2F%2Frtb-private.adkernel.com%2Fuser-synced%3Fuid%3D%7BUID%7D', + '//sync.adkernel.com/user-sync?zone=2&r=%2F%2Frtb.adkernel.com%2Fuser-synced%3Fuid%3D%7BUID%7D', + '//sync.adkernel.com/user-sync?zone=1&r=%2F%2Frtb.adkernel.com%2Fuser-synced%3Fuid%3D%7BUID%7D']; + let userSyncUrls = []; + sandbox.stub(utils, 'createInvisibleIframe', () => { + return {}; + }); + sandbox.stub(utils, 'addEventHandler', (el, ev, cb) => { + userSyncUrls.push(el.src); + cb(); // instant callback + }); doRequest([bid1_zone1, bid2_zone2, bid2_zone2, bid3_host2]); expect(utils.createInvisibleIframe.calledThrice); - let userSyncUrls = utils.createInvisibleIframe.returnValues.map( val => val.src); expect(userSyncUrls).to.be.eql(expectedSyncUrls); }); - }); describe('adapter aliasing', () => { diff --git a/test/spec/modules/admixerBidAdapter_spec.js b/test/spec/modules/admixerBidAdapter_spec.js new file mode 100644 index 00000000000..0b66f8a9469 --- /dev/null +++ b/test/spec/modules/admixerBidAdapter_spec.js @@ -0,0 +1,244 @@ +var chai = require('chai'); +var Adapter = require('modules/admixerBidAdapter')(); +var Ajax = require('src/ajax'); +var bidmanager = require('src/bidmanager.js'); +var CONSTANTS = require('src/constants.json'); + +describe('Admixer adapter', function () { + var validData_1 = { + bids: [ + { + bidder: 'admixer', + bidId: 'bid_id', + params: {zone: 'zone_id'}, + placementCode: 'ad-unit-1', + sizes: [[300, 250], [300, 600]] + } + ] + }; + var validData_2 = { + bids: [ + { + bidder: 'admixer', + bidId: 'bid_id', + params: {zone: 'zone_id'}, + placementCode: 'ad-unit-1', + sizes: [300, 250] + } + ] + }; + var invalidData = { + bids: [ + { + bidder: 'admixer', + bidId: 'bid_id', + params: {}, + placementCode: 'ad-unit-1', + sizes: [[300, 250], [300, 600]] + } + ] + }; + var validVideoData_1 = { + bids: [ + { + mediaType: 'video', + bidder: 'admixer', + bidId: 'bid_id', + params: {zone: 'zone_id'}, + placementCode: 'ad-unit-1', + sizes: [[300, 250], [300, 600]] + } + ] + }; + var validVideoData_2 = { + bids: [ + { + mediaType: 'video', + bidder: 'admixer', + bidId: 'bid_id', + params: {zone: 'zone_id'}, + placementCode: 'ad-unit-1', + sizes: [300, 250] + } + ] + }; + var validVideoData_3 = { + bids: [ + { + mediaType: 'video', + bidder: 'admixer', + bidId: 'bid_id', + params: {zone: 'zone_id', video: {skippable: true}}, + placementCode: 'ad-unit-1', + sizes: [300, 250] + } + ] + }; + var invalidVideoData = { + bids: [ + { + mediaType: 'video', + bidder: 'admixer', + bidId: 'bid_id', + params: {}, + placementCode: 'ad-unit-1', + sizes: [[300, 250], [300, 600]] + } + ] + }; + var responseWithAd = JSON.stringify({ + 'result': { + 'cpm': 2.2, + 'ad': '
response ad
', + 'width': 300, + 'height': 250 + }, + 'callback_uid': 'ad-unit-1' + }); + var responseWithoutAd = JSON.stringify({ + 'result': { + 'cpm': 0, + 'ad': '', + 'width': 0, + 'height': 0 + }, + 'callback_uid': 'ad-unit-1' + }); + var responseWithVideoAd = JSON.stringify({ + 'result': { + 'cpm': 2.2, + 'vastUrl': 'http://inv-nets.admixer.net/vastxml.aspx?req=9d651544-daf4-48ed-ae0c-38a60a4e1920&vk=e914f026449e49aeb6eea07b9642a2ce', + 'width': 300, + 'height': 250 + }, + 'callback_uid': 'ad-unit-1' + }); + var responseWithoutVideoAd = JSON.stringify({ + 'result': { + 'cpm': 0, + 'vastUrl': '', + 'width': 0, + 'height': 0 + }, + 'callback_uid': 'ad-unit-1' + }); + var responseEmpty = ''; + var invUrl = '//inv-nets.admixer.net/prebid.aspx'; + var invVastUrl = '//inv-nets.admixer.net/videoprebid.aspx'; + var validJsonParams = { + zone: 'zone_id', + callback_uid: 'ad-unit-1', + sizes: '300x250-300x600' + }; + var validJsonVideoParams = { + zone: 'zone_id', + callback_uid: 'ad-unit-1', + sizes: '300x250-300x600', + skippable: true + }; + describe('bid request with valid data', function () { + var stubAjax; + beforeEach(function () { + stubAjax = sinon.stub(Ajax, 'ajax'); + }); + + afterEach(function () { + stubAjax.restore(); + }); + it('display: bid request should be called. sizes style -> [[],[]]', function () { + Adapter.callBids(validData_1); + sinon.assert.calledOnce(stubAjax); + }); + it('video: bid request should be called. sizes style -> [[],[]]', function () { + Adapter.callBids(validVideoData_1); + sinon.assert.calledOnce(stubAjax); + }); + it('display: bid request should be called. sizes style -> []', function () { + Adapter.callBids(validData_2); + sinon.assert.calledOnce(stubAjax); + }); + it('video: bid request should be called. sizes style -> []', function () { + Adapter.callBids(validVideoData_2); + sinon.assert.calledOnce(stubAjax); + }); + it('display: ajax params should be matched', function () { + Adapter.callBids(validData_1); + sinon.assert.calledWith(stubAjax, sinon.match(invUrl, function () { + }, validJsonParams, {method: 'GET'})); + }); + it('video: ajax params should be matched', function () { + Adapter.callBids(validVideoData_3); + sinon.assert.calledWith(stubAjax, sinon.match(invVastUrl, function () { + }, validJsonVideoParams, {method: 'GET'})); + }); + }); + describe('bid request with invalid data', function () { + var addBidResponse, stubAjax; + beforeEach(function () { + addBidResponse = sinon.stub(bidmanager, 'addBidResponse'); + stubAjax = sinon.stub(Ajax, 'ajax'); + }); + + afterEach(function () { + addBidResponse.restore(); + stubAjax.restore(); + }); + it('display: ajax shouldn\'t be called', function () { + Adapter.callBids(invalidData); + sinon.assert.notCalled(stubAjax); + }); + it('video: ajax shouldn\'t be called', function () { + Adapter.callBids(invalidVideoData); + sinon.assert.notCalled(stubAjax); + }); + it('display: bidmanager.addBidResponse status code must to be equal "' + CONSTANTS.STATUS.NO_BID + '"', function () { + Adapter.callBids(invalidData); + expect(addBidResponse.firstCall.args[1].getStatusCode()).to.equal(CONSTANTS.STATUS.NO_BID); + expect(addBidResponse.firstCall.args[1].bidderCode).to.equal('admixer'); + }); + it('video: bidmanager.addBidResponse status code must to be equal "' + CONSTANTS.STATUS.NO_BID + '"', function () { + Adapter.callBids(invalidVideoData); + expect(addBidResponse.firstCall.args[1].getStatusCode()).to.equal(CONSTANTS.STATUS.NO_BID); + expect(addBidResponse.firstCall.args[1].bidderCode).to.equal('admixer'); + }); + }); + describe('bid response', function () { + var addBidResponse; + beforeEach(function () { + addBidResponse = sinon.stub(bidmanager, 'addBidResponse'); + }); + afterEach(function () { + addBidResponse.restore(); + }); + it('display: response with ad. bidmanager.addBidResponse status code must to be equal "' + CONSTANTS.STATUS.GOOD + '"', function () { + Adapter.responseCallback(responseWithAd); + var arg = addBidResponse.firstCall.args[1]; + expect(arg.getStatusCode()).to.equal(CONSTANTS.STATUS.GOOD); + expect(arg.bidderCode).to.equal('admixer'); + }); + it('video: response with ad. bidmanager.addBidResponse status code must to be equal "' + CONSTANTS.STATUS.GOOD + '"', function () { + Adapter.responseCallback(responseWithVideoAd); + var arg = addBidResponse.firstCall.args[1]; + expect(arg.getStatusCode()).to.equal(CONSTANTS.STATUS.GOOD); + expect(arg.bidderCode).to.equal('admixer'); + }); + it('display: response without ad. bidmanager.addBidResponse status code must to be equal "' + CONSTANTS.STATUS.NO_BID, function () { + Adapter.responseCallback(responseWithoutAd); + var arg = addBidResponse.firstCall.args[1]; + expect(arg.getStatusCode()).to.equal(CONSTANTS.STATUS.NO_BID); + expect(arg.bidderCode).to.equal('admixer'); + }); + it('video: response without ad. bidmanager.addBidResponse status code must to be equal "' + CONSTANTS.STATUS.NO_BID, function () { + Adapter.responseCallback(responseWithoutVideoAd); + var arg = addBidResponse.firstCall.args[1]; + expect(arg.getStatusCode()).to.equal(CONSTANTS.STATUS.NO_BID); + expect(arg.bidderCode).to.equal('admixer'); + }); + it('display/video: response empty. bidmanager.addBidResponse status code must to be equal "' + CONSTANTS.STATUS.NO_BID, function () { + Adapter.responseCallback(responseEmpty); + var arg = addBidResponse.firstCall.args[1]; + expect(arg.getStatusCode()).to.equal(CONSTANTS.STATUS.NO_BID); + expect(arg.bidderCode).to.equal('admixer'); + }); + }); +}); diff --git a/test/spec/modules/adsupplyBidAdapter_spec.js b/test/spec/modules/adsupplyBidAdapter_spec.js new file mode 100644 index 00000000000..4d089aaa0ef --- /dev/null +++ b/test/spec/modules/adsupplyBidAdapter_spec.js @@ -0,0 +1,359 @@ +describe('adsupply adapter tests', function () { + const expect = require('chai').expect; + + const AdSupplyAdapter = require('../../../modules/adsupplyBidAdapter'); + const adloader = require('../../../src/adloader'); + const bidmanager = require('../../../src/bidmanager'); + const CONSTANTS = require('../../../src/constants.json'); + let adsupplyAdapter = new AdSupplyAdapter(); + + beforeEach(() => { + pbjs._bidsRequested = []; + }); + + it('adsupply response handler should exist and be a function', function () { + expect(pbjs.adSupplyResponseHandler).to.exist.and.to.be.a('function'); + }); + + it('two requests are sent to adsupply engine', function () { + let stubLoadScript = sinon.stub(adloader, 'loadScript'); + + let request = { + bids: [{ + placementCode: 'pc1', + bidder: 'adsupply', + bidId: 'bidId1', + params: { + zoneId: 111, + clientId: 'g32db6906-55f4-42b1-a7d2-7dfaddce96fd', + siteId: '0ab16161-a1de-4683-8837-c420bd4387c0', + endpointUrl: 'engine.4dsply.com' + } + }, + { + placementCode: 'pc2', + bidder: 'adsupply', + bidId: 'bidId2', + params: { + clientId: 'g32db6906-55f4-42b1-a7d2-7dfaddce96fd', + zoneId: 222, + siteId: '0ab16161-a1de-4683-8837-c420bd4387c0', + endpointUrl: 'engine.4dsply.com' + } + }] + }; + + adsupplyAdapter.callBids(request); + + sinon.assert.calledTwice(stubLoadScript); + + adloader.loadScript.restore(); + }); + + it('zoneId is not a number and not specified', function () { + let stubLoadScript = sinon.stub(adloader, 'loadScript'); + + let request = { + bids: [{ + placementCode: 'pc1', + bidder: 'adsupply', + bidId: 'bidId1', + params: { + clientId: 'g32db6906-55f4-42b1-a7d2-7dfaddce96fd', + zoneId: '111', + siteId: '0ab16161-a1de-4683-8837-c420bd4387c0', + endpointUrl: 'engine.4dsply.com' + } + }, + { + placementCode: 'pc2', + bidder: 'adsupply', + bidId: 'bidId2', + params: { + clientId: 'g32db6906-55f4-42b1-a7d2-7dfaddce96fd', + siteId: '0ab16161-a1de-4683-8837-c420bd4387c0', + endpointUrl: 'engine.4dsply.com' + } + }] + }; + + adsupplyAdapter.callBids(request); + + sinon.assert.notCalled(stubLoadScript); + + adloader.loadScript.restore(); + }); + + it('siteId is empty and not specified', function () { + let stubLoadScript = sinon.stub(adloader, 'loadScript'); + + let request = { + bids: [{ + placementCode: 'pc1', + bidder: 'adsupply', + bidId: 'bidId1', + params: { + zoneId: 111, + siteId: '', + clientId: 'g32db6906-55f4-42b1-a7d2-7dfaddce96fd', + endpointUrl: 'engine.4dsply.com' + } + }, + { + placementCode: 'pc2', + bidder: 'adsupply', + bidId: 'bidId2', + params: { + zoneId: 222, + clientId: 'g32db6906-55f4-42b1-a7d2-7dfaddce96fd', + endpointUrl: 'engine.4dsply.com' + } + }] + }; + + adsupplyAdapter.callBids(request); + + sinon.assert.notCalled(stubLoadScript); + + adloader.loadScript.restore(); + }); + + it('endpointUrl is empty and not specified', function () { + let stubLoadScript = sinon.stub(adloader, 'loadScript'); + + let request = { + bids: [{ + placementCode: 'pc1', + bidder: 'adsupply', + bidId: 'bidId1', + params: { + clientId: 'g32db6906-55f4-42b1-a7d2-7dfaddce96fd', + zoneId: 111, + siteId: '0ab16161-a1de-4683-8837-c420bd4387c0', + endpointUrl: '' + } + }, + { + placementCode: 'pc2', + bidder: 'adsupply', + bidId: 'bidId2', + params: { + clientId: 'g32db6906-55f4-42b1-a7d2-7dfaddce96fd', + zoneId: 222, + siteId: '0ab16161-a1de-4683-8837-c420bd4387c0', + } + }] + }; + + adsupplyAdapter.callBids(request); + + sinon.assert.notCalled(stubLoadScript); + + adloader.loadScript.restore(); + }); + + it('clientId is empty and not specified', function () { + let stubLoadScript = sinon.stub(adloader, 'loadScript'); + + let request = { + bids: [{ + placementCode: 'pc1', + bidder: 'adsupply', + bidId: 'bidId1', + params: { + clientId: '', + zoneId: 111, + siteId: '0ab16161-a1de-4683-8837-c420bd4387c0', + endpointUrl: 'engine.4dsply.com' + } + }, + { + placementCode: 'pc2', + bidder: 'adsupply', + bidId: 'bidId2', + params: { + zoneId: 222, + siteId: '0ab16161-a1de-4683-8837-c420bd4387c0', + endpointUrl: 'engine.4dsply.com' + } + }] + }; + + adsupplyAdapter.callBids(request); + + sinon.assert.notCalled(stubLoadScript); + + adloader.loadScript.restore(); + }); + + it('parameters are missed', function () { + let stubLoadScript = sinon.stub(adloader, 'loadScript'); + + let request = { + bids: [{ + placementCode: 'pc1', + bidder: 'adsupply', + bidId: 'bidId1' + }] + }; + + adsupplyAdapter.callBids(request); + + sinon.assert.notCalled(stubLoadScript); + + adloader.loadScript.restore(); + }); + + it('Parameters added to the request url', function () { + let stubLoadScript = sinon.stub(adloader, 'loadScript'); + + let request = { + bids: [{ + placementCode: 'pc1', + bidder: 'adsupply', + bidId: 'bidId1', + params: { + zoneId: 111, + clientId: 'g32db6906-55f4-42b1-a7d2-7dfaddce96fd', + siteId: '0ab16161-a1de-4683-8837-c420bd4387c0', + endpointUrl: 'engine.4dsply.com' + } + }] + }; + + adsupplyAdapter.callBids(request); + + var requestUrl = stubLoadScript.getCall(0).args[0]; + expect(requestUrl).to.contain('111'); + expect(requestUrl).to.contain('0ab16161-a1de-4683-8837-c420bd4387c0'); + expect(requestUrl).to.contain('engine.4dsply.com'); + expect(requestUrl).to.contain('&hbt=1'); + expect(requestUrl).to.contain('g32db6906-55f4-42b1-a7d2-7dfaddce96fd'); + + adloader.loadScript.restore(); + }); + + it('Response handler invalid data', function () { + let stubAddBidResponse = sinon.stub(bidmanager, 'addBidResponse'); + + // adapter needs to be called, in order for the stub to register. + new AdSupplyAdapter(); + + // bidId is not valid + pbjs.adSupplyResponseHandler(null); + + // bidRequest object is not found + pbjs.adSupplyResponseHandler('bidId1'); + + let clientId = 'g5d384afa-c050-4bac-b202-dab8fb06e381'; + // Zone property is not found + let bidderRequest = { + bidderCode: 'adsupply', + bids: [{ + placementCode: 'pc1', + bidder: 'adsupply', + bidId: 'bidId1', + params: { + clientId: clientId, + zoneId: 111, + siteId: '0ab16161-a1de-4683-8837-c420bd4387c0', + endpointUrl: 'engine.4dsply.com' + } + }] + }; + pbjs._bidsRequested.push(bidderRequest); + pbjs.adSupplyResponseHandler('bidId1'); + + // Media is not found + window[clientId] = window[clientId] || {}; + window[clientId]['b111'] = window[clientId]['b111'] || {}; + pbjs.adSupplyResponseHandler('bidId1'); + + sinon.assert.notCalled(stubAddBidResponse); + + pbjs._bidsRequested.pop(); + bidmanager.addBidResponse.restore(); + }); + + it('No Fill response', function () { + let stubAddBidResponse = sinon.stub(bidmanager, 'addBidResponse'); + // adapter needs to be called, in order for the stub to register. + new AdSupplyAdapter(); + + let clientId = 'g5d384afa-c050-4bac-b202-dab8fb06e381'; + // Zone property is not found + let bidderRequest = { + bidderCode: 'adsupply', + bids: [{ + placementCode: 'pc1', + bidder: 'adsupply', + bidId: 'bidId1', + params: { + clientId: clientId, + zoneId: 111, + siteId: '0ab16161-a1de-4683-8837-c420bd4387c0', + endpointUrl: 'engine.4dsply.com' + } + }] + }; + + pbjs._bidsRequested.push(bidderRequest); + + window[clientId] = window[clientId] || {}; + window[clientId]['b111'] = window[clientId]['b111'] || {}; + window[clientId]['b111'].Media = { width: 300 }; + pbjs.adSupplyResponseHandler('bidId1'); + + sinon.assert.calledOnce(stubAddBidResponse); + + let bidPlacementCode = stubAddBidResponse.getCall(0).args[0]; + let bidResponse = stubAddBidResponse.getCall(0).args[1]; + expect(bidPlacementCode).to.equal('pc1'); + expect(bidResponse.getStatusCode()).to.equal(CONSTANTS.STATUS.NO_BID); + expect(bidResponse.bidderCode).to.equal('adsupply'); + + pbjs._bidsRequested.pop(); + bidmanager.addBidResponse.restore(); + }); + + it('Fill response', function () { + let stubAddBidResponse = sinon.stub(bidmanager, 'addBidResponse'); + // adapter needs to be called, in order for the stub to register. + new AdSupplyAdapter(); + + let clientId = 'g5d384afa-c050-4bac-b202-dab8fb06e381'; + // Zone property is not found + let bidderRequest = { + bidderCode: 'adsupply', + bids: [{ + placementCode: 'pc1', + bidder: 'adsupply', + bidId: 'bidId1', + params: { + clientId: clientId, + zoneId: 111, + siteId: '0ab16161-a1de-4683-8837-c420bd4387c0', + endpointUrl: 'engine.4dsply.com' + } + }] + }; + + pbjs._bidsRequested.push(bidderRequest); + + window[clientId] = window[clientId] || {}; + window[clientId]['b111'] = window[clientId]['b111'] || {}; + window[clientId]['b111'].Media = { Width: 300, Height: 250, Url: '/Redirect.engine', Ecpm: 0.0012 }; + pbjs.adSupplyResponseHandler('bidId1'); + + sinon.assert.calledOnce(stubAddBidResponse); + + let bidPlacementCode = stubAddBidResponse.getCall(0).args[0]; + let bidResponse = stubAddBidResponse.getCall(0).args[1]; + expect(bidPlacementCode).to.equal('pc1'); + expect(bidResponse.getStatusCode()).to.equal(CONSTANTS.STATUS.GOOD); + expect(bidResponse.bidderCode).to.equal('adsupply'); + + pbjs._bidsRequested.pop(); + bidmanager.addBidResponse.restore(); + }); +}); diff --git a/test/spec/modules/adyoulikeBidAdapter_spec.js b/test/spec/modules/adyoulikeBidAdapter_spec.js new file mode 100644 index 00000000000..539fd2da85c --- /dev/null +++ b/test/spec/modules/adyoulikeBidAdapter_spec.js @@ -0,0 +1,308 @@ +import { expect } from 'chai'; +import { parse } from '../../../src/url'; +import AdyoulikAdapter from '../../../modules/adyoulikeBidAdapter'; +import bidmanager from 'src/bidmanager'; +import { STATUS } from 'src/constants'; + +describe('Adyoulike Adapter', () => { + const endpoint = 'http://hb-api.omnitagjs.com/hb-api/prebid'; + const canonicalUrl = 'http://canonical.url/?t=%26'; + const bidderCode = 'adyoulike'; + const bidRequestWithEmptyPlacement = { + 'bidderCode': 'adyoulike', + 'bids': [ + { + 'bidId': 'bid_id_0', + 'bidder': 'adyoulike', + 'placementCode': 'adunit/hb-0', + 'params': {}, + 'sizes': '300x250' + } + ], + }; + const bidRequestWithEmptySizes = { + 'bidderCode': 'adyoulike', + 'bids': [ + { + 'bidId': 'bid_id_0', + 'bidder': 'adyoulike', + 'placementCode': 'adunit/hb-0', + 'params': { + 'placement': 'placement_0' + } + } + ], + }; + const bidRequestWithSinglePlacement = { + 'bidderCode': 'adyoulike', + 'bids': [ + { + 'bidId': 'bid_id_0', + 'bidder': 'adyoulike', + 'placementCode': 'adunit/hb-0', + 'params': { + 'placement': 'placement_0' + }, + 'sizes': '300x250' + } + ], + }; + const bidRequestMultiPlacements = { + 'bidderCode': 'adyoulike', + 'bids': [ + { + 'bidId': 'bid_id_0', + 'bidder': 'adyoulike', + 'placementCode': 'adunit/hb-0', + 'params': { + 'placement': 'placement_0' + }, + 'sizes': '300x250' + }, + { + 'bidId': 'bid_id_1', + 'bidder': 'adyoulike', + 'placementCode': 'adunit/hb-1', + 'params': { + 'placement': 'placement_1' + }, + 'sizes': [[300, 600]] + }, + { + 'bidId': 'bid_id_2', + 'bidder': 'adyoulike', + 'placementCode': 'adunit/hb-2', + 'params': {}, + 'sizes': '300x400' + }, + { + 'bidId': 'bid_id_3', + 'bidder': 'adyoulike', + 'placementCode': 'adunit/hb-3', + 'params': { + 'placement': 'placement_3' + } + } + ], + }; + + const responseWithEmptyPlacement = [ + { + 'Placement': 'placement_0' + } + ]; + const responseWithSinglePlacement = [ + { + 'Placement': 'placement_0', + 'Banner': 'placement_0', + 'Price': 0.5 + } + ]; + const responseWithMultiplePlacements = [ + { + 'Placement': 'placement_0', + 'Banner': 'placement_0', + 'Price': 0.5 + }, + { + 'Placement': 'placement_1', + 'Banner': 'placement_1', + 'Price': 0.6 + } + ]; + + let adapter; + + beforeEach(() => { + adapter = new AdyoulikAdapter(); + }); + + describe('adapter public API', () => { + const adapter = AdyoulikAdapter.createNew(); + it('createNew', () => { + expect(adapter.createNew).to.be.a('function'); + }); + + it('setBidderCode', () => { + expect(adapter.setBidderCode).to.be.a('function'); + }); + it('callBids', () => { + expect(adapter.setBidderCode).to.be.a('function'); + }); + }); + + describe('request function', () => { + let requests; + let xhr; + let addBidResponse; + let canonicalQuery; + + beforeEach(() => { + requests = []; + + xhr = sinon.useFakeXMLHttpRequest(); + xhr.onCreate = request => requests.push(request); + + addBidResponse = sinon.stub(bidmanager, 'addBidResponse'); + + let canonical = document.createElement('link'); + canonical.rel = 'canonical'; + canonical.href = canonicalUrl; + canonicalQuery = sinon.stub(window.top.document.head, 'querySelector'); + canonicalQuery.withArgs('link[rel="canonical"][href]').returns(canonical); + }); + + afterEach(() => { + xhr.restore(); + bidmanager.addBidResponse.restore(); + canonicalQuery.restore(); + }); + + it('requires placement request', () => { + adapter.callBids(bidRequestWithEmptyPlacement); + expect(requests).to.be.empty; + expect(addBidResponse.calledOnce).to.equal(false); + }); + + it('requires sizes in request', () => { + adapter.callBids(bidRequestWithEmptySizes); + expect(requests).to.be.empty; + expect(addBidResponse.calledOnce).to.equal(false); + }); + + it('sends bid request to endpoint with single placement', () => { + adapter.callBids(bidRequestWithSinglePlacement); + expect(requests[0].url).to.contain(endpoint); + expect(requests[0].method).to.equal('POST'); + + expect(requests[0].url).to.contains('CanonicalUrl=' + encodeURIComponent(canonicalUrl)); + + let body = JSON.parse(requests[0].requestBody); + expect(body.Version).to.equal('0.1'); + expect(body.Placements).deep.equal(['placement_0']); + expect(body.PageRefreshed).to.equal(false); + }); + + it('sends bid request to endpoint with single placement without canonical', () => { + canonicalQuery.restore(); + + adapter.callBids(bidRequestWithSinglePlacement); + expect(requests[0].url).to.contain(endpoint); + expect(requests[0].method).to.equal('POST'); + + expect(requests[0].url).to.not.contains('CanonicalUrl=' + encodeURIComponent(canonicalUrl)); + + let body = JSON.parse(requests[0].requestBody); + expect(body.Version).to.equal('0.1'); + expect(body.Placements).deep.equal(['placement_0']); + expect(body.PageRefreshed).to.equal(false); + }); + + it('sends bid request to endpoint with multiple placements', () => { + adapter.callBids(bidRequestMultiPlacements); + expect(requests[0].url).to.contain(endpoint); + expect(requests[0].method).to.equal('POST'); + + expect(requests[0].url).to.contains('CanonicalUrl=' + encodeURIComponent(canonicalUrl)); + + let body = JSON.parse(requests[0].requestBody); + expect(body.Version).to.equal('0.1'); + expect(body.Placements).deep.equal(['placement_0', 'placement_1']); + expect(body.PageRefreshed).to.equal(false); + }); + }); + + describe('response function', () => { + let server; + let addBidResponse; + + beforeEach(() => { + server = sinon.fakeServer.create(); + addBidResponse = sinon.stub(bidmanager, 'addBidResponse'); + }); + + afterEach(() => { + server.restore(); + bidmanager.addBidResponse.restore(); + }); + + it('invalid json', () => { + server.respondWith('{'); + adapter.callBids(bidRequestWithSinglePlacement); + server.respond(); + + expect(addBidResponse.calledOnce).to.equal(true); + expect(addBidResponse.args[0]).to.have.lengthOf(2); + expect(addBidResponse.args[0][1].getStatusCode()).to.equal(STATUS.NO_BID); + expect(addBidResponse.args[0][1].bidderCode).to.equal(bidderCode); + }); + + it('receive reponse with empty placement', () => { + server.respondWith(JSON.stringify(responseWithEmptyPlacement)); + adapter.callBids(bidRequestWithSinglePlacement); + server.respond(); + + expect(addBidResponse.calledOnce).to.equal(true); + expect(addBidResponse.args[0]).to.have.lengthOf(2); + expect(addBidResponse.args[0][1].getStatusCode()).to.equal(STATUS.NO_BID); + expect(addBidResponse.args[0][1].bidderCode).to.equal(bidderCode); + }); + + it('receive reponse with single placement', () => { + server.respondWith(JSON.stringify(responseWithSinglePlacement)); + adapter.callBids(bidRequestWithSinglePlacement); + server.respond(); + + expect(addBidResponse.calledOnce).to.equal(true); + expect(addBidResponse.args[0]).to.have.lengthOf(2); + expect(addBidResponse.args[0][1].getStatusCode()).to.equal(STATUS.GOOD); + expect(addBidResponse.args[0][1].cpm).to.equal(0.5); + expect(addBidResponse.args[0][1].ad).to.equal('placement_0'); + expect(addBidResponse.args[0][1].width).to.equal(300); + expect(addBidResponse.args[0][1].height).to.equal(250); + }); + + it('receive reponse with multiple placement', () => { + server.respondWith(JSON.stringify(responseWithMultiplePlacements)); + adapter.callBids(bidRequestMultiPlacements); + server.respond(); + + expect(addBidResponse.calledTwice).to.equal(true); + + expect(addBidResponse.args[0]).to.have.lengthOf(2); + expect(addBidResponse.args[0][1].getStatusCode()).to.equal(STATUS.GOOD); + expect(addBidResponse.args[0][1].bidderCode).to.equal(bidderCode); + expect(addBidResponse.args[0][1].cpm).to.equal(0.5); + expect(addBidResponse.args[0][1].ad).to.equal('placement_0'); + expect(addBidResponse.args[0][1].width).to.equal(300); + expect(addBidResponse.args[0][1].height).to.equal(250); + + expect(addBidResponse.args[1]).to.have.lengthOf(2); + expect(addBidResponse.args[1][1].getStatusCode()).to.equal(STATUS.GOOD); + expect(addBidResponse.args[1][1].bidderCode).to.equal(bidderCode); + expect(addBidResponse.args[1][1].cpm).to.equal(0.6); + expect(addBidResponse.args[1][1].ad).to.equal('placement_1'); + expect(addBidResponse.args[1][1].width).to.equal(300); + expect(addBidResponse.args[1][1].height).to.equal(600); + }); + + it('receive reponse with invalid placement number', () => { + server.respondWith(JSON.stringify(responseWithSinglePlacement)); + adapter.callBids(bidRequestMultiPlacements); + server.respond(); + + expect(addBidResponse.calledTwice).to.equal(true); + + expect(addBidResponse.args[0]).to.have.lengthOf(2); + expect(addBidResponse.args[0][1].getStatusCode()).to.equal(STATUS.GOOD); + expect(addBidResponse.args[0][1].bidderCode).to.equal(bidderCode); + expect(addBidResponse.args[0][1].cpm).to.equal(0.5); + expect(addBidResponse.args[0][1].ad).to.equal('placement_0'); + expect(addBidResponse.args[0][1].width).to.equal(300); + expect(addBidResponse.args[0][1].height).to.equal(250); + + expect(addBidResponse.args[1]).to.have.lengthOf(2); + expect(addBidResponse.args[1][1].getStatusCode()).to.equal(STATUS.NO_BID); + }); + }); +}); diff --git a/test/spec/unit/adapters/analytics/aol_spec.js b/test/spec/modules/aolAnalyticsAdapter_spec.js similarity index 96% rename from test/spec/unit/adapters/analytics/aol_spec.js rename to test/spec/modules/aolAnalyticsAdapter_spec.js index b4fd7c5c4c3..ec67de14fb3 100644 --- a/test/spec/unit/adapters/analytics/aol_spec.js +++ b/test/spec/modules/aolAnalyticsAdapter_spec.js @@ -1,8 +1,8 @@ // Copyright 2016 AOL Platforms. -import { expect } from 'chai'; -import events from '../../../../../src/events'; -import CONSTANTS from '../../../../../src/constants.json'; +import {expect} from 'chai'; +import events from 'src/events'; +import CONSTANTS from 'src/constants.json'; import { DEFAULT_REQUEST_TIMESTAMP, DEFAULT_REQUEST_ID, @@ -12,10 +12,9 @@ import { BID_CONFIGS, BID_SETS, BIDS, -} from '../../../../fixtures/fixturesAnalytics'; - -const utils = require('../../../../../src/utils'); -const aolAnalytics = require('../../../../../src/adapters/analytics/aol').default; +} from 'test/fixtures/fixturesAnalytics'; +import * as utils from 'src/utils'; +import aolAnalytics from 'modules/aolAnalyticsAdapter'; const AUCTION_END = CONSTANTS.EVENTS.AUCTION_END; const BID_WON = CONSTANTS.EVENTS.BID_WON; @@ -25,7 +24,6 @@ const ANALYTICS_EVENTS = { }; describe('AOL analytics adapter', () => { - before(() => { aolAnalytics.enableAnalytics({}); }); @@ -49,15 +47,15 @@ describe('AOL analytics adapter', () => { start: DEFAULT_REQUEST_TIMESTAMP, timeout: DEFAULT_TIMEOUT, bids: adUnits.map(adUnit => adUnit.bids - .filter(bid => bid.bidder === bidderCode) - .map(bid => Object.assign({}, bid, { - placementCode: adUnit.code, - bidId: utils.getUniqueIdentifierStr(), - bidderRequestId: bidderRequestId, - requestId: DEFAULT_REQUEST_ID, - sizes: adUnit.sizes - })) - ) + .filter(bid => bid.bidder === bidderCode) + .map(bid => Object.assign({}, bid, { + placementCode: adUnit.code, + bidId: utils.getUniqueIdentifierStr(), + bidderRequestId: bidderRequestId, + requestId: DEFAULT_REQUEST_ID, + sizes: adUnit.sizes + })) + ) .reduce(utils.flatten, []) }; }); @@ -139,7 +137,7 @@ describe('AOL analytics adapter', () => { }); let bidsReceived = [validBidReceived]; - aolAnalytics.reportAuctionEvent({ adUnitsConfig, bidsRequested, bidsReceived }); + aolAnalytics.reportAuctionEvent({adUnitsConfig, bidsRequested, bidsReceived}); expect(aolAnalytics.reportEvent.calledOnce).to.be.true; expect(aolAnalytics.reportEvent.calledWith(1)).to.be.true; @@ -157,7 +155,7 @@ describe('AOL analytics adapter', () => { }); let bidsReceived = [emptyBidReceived]; - aolAnalytics.reportAuctionEvent({ adUnitsConfig, bidsRequested, bidsReceived }); + aolAnalytics.reportAuctionEvent({adUnitsConfig, bidsRequested, bidsReceived}); expect(aolAnalytics.reportEvent.calledOnce).to.be.true; expect(aolAnalytics.reportEvent.calledWith(1)).to.be.true; @@ -171,7 +169,7 @@ describe('AOL analytics adapter', () => { let bidsRequested = [BID_SETS.AOL]; let bidsReceived = []; - aolAnalytics.reportAuctionEvent({ adUnitsConfig, bidsRequested, bidsReceived }); + aolAnalytics.reportAuctionEvent({adUnitsConfig, bidsRequested, bidsReceived}); expect(aolAnalytics.reportEvent.calledOnce).to.be.true; expect(aolAnalytics.reportEvent.calledWith(1)).to.be.true; @@ -201,7 +199,7 @@ describe('AOL analytics adapter', () => { }) ]; - aolAnalytics.reportAuctionEvent({ adUnitsConfig, bidsRequested, bidsReceived }); + aolAnalytics.reportAuctionEvent({adUnitsConfig, bidsRequested, bidsReceived}); expect(aolAnalytics.reportEvent.calledOnce).to.be.true; expect(aolAnalytics.reportEvent.calledWith(1)).to.be.true; @@ -221,7 +219,7 @@ describe('AOL analytics adapter', () => { let bidsRequested = createRequestedBids(adUnitsConfig); let bidsReceived = []; - aolAnalytics.reportAuctionEvent({ adUnitsConfig, bidsRequested, bidsReceived }); + aolAnalytics.reportAuctionEvent({adUnitsConfig, bidsRequested, bidsReceived}); expect(aolAnalytics.reportEvent.calledOnce).to.be.true; expect(aolAnalytics.reportEvent.calledWith(1)).to.be.true; @@ -264,7 +262,7 @@ describe('AOL analytics adapter', () => { }) ]; - aolAnalytics.reportAuctionEvent({ adUnitsConfig, bidsRequested, bidsReceived }); + aolAnalytics.reportAuctionEvent({adUnitsConfig, bidsRequested, bidsReceived}); expect(aolAnalytics.reportEvent.calledOnce).to.be.true; expect(aolAnalytics.reportEvent.calledWith(1)).to.be.true; @@ -303,7 +301,7 @@ describe('AOL analytics adapter', () => { }) ]; - aolAnalytics.reportAuctionEvent({ adUnitsConfig, bidsRequested, bidsReceived }); + aolAnalytics.reportAuctionEvent({adUnitsConfig, bidsRequested, bidsReceived}); expect(aolAnalytics.reportEvent.calledOnce).to.be.true; expect(aolAnalytics.reportEvent.calledWith(1)).to.be.true; @@ -326,7 +324,7 @@ describe('AOL analytics adapter', () => { let bidsRequested = [BID_SETS.AOL]; let bidsReceived = [BIDS.VALID]; - aolAnalytics.reportAuctionEvent({ adUnitsConfig, bidsRequested, bidsReceived }); + aolAnalytics.reportAuctionEvent({adUnitsConfig, bidsRequested, bidsReceived}); expect(aolAnalytics.adUnits) .to.have.property(DEFAULT_AD_UNIT_CODE) @@ -372,7 +370,7 @@ describe('AOL analytics adapter', () => { }) ]; - aolAnalytics.reportAuctionEvent({ adUnitsConfig, bidsRequested, bidsReceived }); + aolAnalytics.reportAuctionEvent({adUnitsConfig, bidsRequested, bidsReceived}); expect(aolAnalytics.reportEvent.calledTwice).to.be.true; let call1 = aolAnalytics.reportEvent.getCall(0); @@ -430,7 +428,7 @@ describe('AOL analytics adapter', () => { }) ]; - aolAnalytics.reportAuctionEvent({ adUnitsConfig, bidsRequested, bidsReceived }); + aolAnalytics.reportAuctionEvent({adUnitsConfig, bidsRequested, bidsReceived}); expect(aolAnalytics.reportEvent.calledOnce).to.be.true; expect(aolAnalytics.reportEvent.calledWith(1)).to.be.true; @@ -478,7 +476,7 @@ describe('AOL analytics adapter', () => { }) ]; - aolAnalytics.reportAuctionEvent({ adUnitsConfig, bidsRequested, bidsReceived }); + aolAnalytics.reportAuctionEvent({adUnitsConfig, bidsRequested, bidsReceived}); expect(aolAnalytics.reportEvent.calledOnce).to.be.true; expect(aolAnalytics.reportEvent.calledWith(1)).to.be.true; @@ -529,7 +527,7 @@ describe('AOL analytics adapter', () => { }) ]; - aolAnalytics.reportAuctionEvent({ adUnitsConfig, bidsRequested, bidsReceived }); + aolAnalytics.reportAuctionEvent({adUnitsConfig, bidsRequested, bidsReceived}); expect(aolAnalytics.reportEvent.calledOnce).to.be.true; expect(aolAnalytics.reportEvent.calledWith(1)).to.be.true; @@ -731,7 +729,7 @@ describe('AOL analytics adapter', () => { 'header-bid-tag-1': winningAdUnit, 'header-bid-tag-2': {} }; - aolAnalytics.reportWinEvent({ winningBid }); + aolAnalytics.reportWinEvent({winningBid}); expect(aolAnalytics.reportEvent.calledOnce).to.be.true; expect(aolAnalytics.reportEvent.calledWith(ANALYTICS_EVENTS.WIN, winningAdUnit)).to.be.true; @@ -758,7 +756,7 @@ describe('AOL analytics adapter', () => { it('should build event URL', () => { let event = AUCTION_END; - let adUnit = { foo: 'bar' }; + let adUnit = {foo: 'bar'}; aolAnalytics.reportEvent(event, adUnit); @@ -768,7 +766,7 @@ describe('AOL analytics adapter', () => { it('make AJAX call', () => { let event = AUCTION_END; - let adUnit = { foo: 'bar' }; + let adUnit = {foo: 'bar'}; aolAnalytics.buildEventUrl.returns('http://www.example.com/'); aolAnalytics.reportEvent(event, adUnit); @@ -949,7 +947,7 @@ describe('AOL analytics adapter', () => { it('should build url with hbcur parameter if set', () => { let bid = BIDS.VALID; let url = aolAnalytics.buildEventUrl(ANALYTICS_EVENTS.AUCTION, { - aolParams: Object.assign({}, BID_CONFIGS.AOL1.params, { currencyCode: 'USD' }), + aolParams: Object.assign({}, BID_CONFIGS.AOL1.params, {currencyCode: 'USD'}), bids: [bid], winner: bid }); @@ -969,7 +967,7 @@ describe('AOL analytics adapter', () => { it('should build url with pubapi parameter if set', () => { let bid = BIDS.VALID; let url = aolAnalytics.buildEventUrl(ANALYTICS_EVENTS.AUCTION, { - aolParams: Object.assign({}, BID_CONFIGS.AOL1.params, { pubapiId: 456 }), + aolParams: Object.assign({}, BID_CONFIGS.AOL1.params, {pubapiId: 456}), bids: [bid], winner: bid }); @@ -1398,7 +1396,6 @@ describe('AOL analytics adapter', () => { adUnit.code = 'ad@code+'; adUnit.adIdExtension = '$test&@adI#d/post=fix+encoding'; - expect(aolAnalytics.generateAdId(adUnit)).to.equal(encodeURIComponent(adUnit.code + '-' + adUnit.adIdExtension)); }); }); diff --git a/test/spec/adapters/aol_spec.js b/test/spec/modules/aolBidAdapter_spec.js similarity index 75% rename from test/spec/adapters/aol_spec.js rename to test/spec/modules/aolBidAdapter_spec.js index 87f0f2e428d..01db70a24a2 100644 --- a/test/spec/adapters/aol_spec.js +++ b/test/spec/modules/aolBidAdapter_spec.js @@ -1,28 +1,55 @@ import {expect} from 'chai'; import * as utils from 'src/utils'; -import AolAdapter from 'src/adapters/aol'; +import AolAdapter from 'modules/aolBidAdapter'; import bidmanager from 'src/bidmanager'; - let getDefaultBidResponse = () => { return { - "id": "245730051428950632", - "cur": "USD", - "seatbid": [{ - "bid": [{ - "id": 1, - "impid": "245730051428950632", - "price": 0.09, - "adm": "", - "crid": "0", - "h": 90, - "w": 728, - "ext": {"sizeid": 225} + id: '245730051428950632', + cur: 'USD', + seatbid: [{ + bid: [{ + id: 1, + impid: '245730051428950632', + price: 0.09, + adm: '', + crid: '0', + h: 90, + w: 728, + ext: {sizeid: 225} }] }] }; }; +let getMarketplaceBidParams = () => { + return { + placement: 1234567, + network: '9599.1' + }; +}; + +let getNexageGetBidParams = () => { + return { + dcn: '2c9d2b50015c5ce9db6aeeed8b9500d6', + pos: 'header' + }; +}; + +let getNexagePostBidParams = () => { + return { + id: 'id-1', + imp: [{ + id: 'id-2', + banner: { + w: '100', + h: '100' + }, + tagid: 'header1' + }] + }; +}; + let getDefaultBidRequest = () => { return { bidderCode: 'aol', @@ -35,22 +62,21 @@ let getDefaultBidRequest = () => { bidderRequestId: '7101db09af0db2', requestId: 'd3e07445-ab06-44c8-a9dd-5ef9af06d2a6', placementCode: 'foo', - params: { - placement: 1234567, - network: '9599.1' - } + params: getMarketplaceBidParams() }] }; }; describe('AolAdapter', () => { + const MARKETPLACE_URL = 'adserver-us.adtech.advertising.com/pubapi/3.0/'; + const NEXAGE_URL = 'hb.nexage.com/bidRequest?'; let adapter; beforeEach(() => adapter = new AolAdapter()); function createBidderRequest({bids, params} = {}) { - var bidderRequest = utils.cloneJson(getDefaultBidRequest()); + var bidderRequest = getDefaultBidRequest(); if (bids && Array.isArray(bids)) { bidderRequest.bids = bids; } @@ -66,9 +92,7 @@ describe('AolAdapter', () => { }); describe('bid request', () => { - describe('Marketplace api', () => { - let xhr; let requests; @@ -87,7 +111,57 @@ describe('AolAdapter', () => { it('should hit the Marketplace api endpoint with the Marketplace config', () => { adapter.callBids(getDefaultBidRequest()); - expect(requests[0].url).to.contain('adserver-us.adtech.advertising.com/pubapi/3.0/'); + expect(requests[0].url).to.contain(MARKETPLACE_URL); + }); + + it('should hit the Marketplace via onedisplay bidder code', () => { + let bidRequest = createBidderRequest({ + bids: [{ + bidder: 'onedisplay' + }], + params: getMarketplaceBidParams() + }); + + adapter.callBids(bidRequest); + expect(requests[0].url).to.contain(MARKETPLACE_URL); + }); + + it('should hit the Marketplace via onedisplay bidder code when Marketplace and Nexage params are present', () => { + let bidParams = Object.assign(getMarketplaceBidParams(), getNexageGetBidParams()); + let bidRequest = createBidderRequest({ + bids: [{ + bidder: 'onedisplay' + }], + params: bidParams + }); + + adapter.callBids(bidRequest); + expect(requests[0].url).to.contain(MARKETPLACE_URL); + }); + + it('should hit the Marketplace via onedisplay bidder code when Nexage params are present', () => { + let bidParams = Object.assign(getMarketplaceBidParams(), getNexageGetBidParams(), getNexagePostBidParams()); + let bidRequest = createBidderRequest({ + bids: [{ + bidder: 'onedisplay' + }], + params: bidParams + }); + + adapter.callBids(bidRequest); + expect(requests[0].url).to.contain(MARKETPLACE_URL); + }); + + it('should not resolve endpoint for onedisplay bidder code when only Nexage params are present', () => { + let bidParams = Object.assign(getNexageGetBidParams(), getNexagePostBidParams()); + + adapter.callBids(createBidderRequest({ + bids: [{ + bidder: 'onedisplay' + }], + params: bidParams + })); + expect(requests.length).to.equal(0); }); it('should hit endpoint based on the region config option', () => { @@ -109,7 +183,7 @@ describe('AolAdapter', () => { region: 'an' } })); - expect(requests[0].url).to.contain('adserver-us.adtech.advertising.com/pubapi/3.0/'); + expect(requests[0].url).to.contain(MARKETPLACE_URL); }); it('should hit endpoint based on the server config option', () => { @@ -221,10 +295,25 @@ describe('AolAdapter', () => { })); expect(requests[0].url).to.contain('bidfloor=0.8'); }); + + it('should contain key values if keyValues param is present', () => { + adapter.callBids(createBidderRequest({ + params: { + placement: 1234567, + network: '9599.1', + keyValues: { + age: 25, + height: 3.42, + test: 'key' + } + } + })); + + expect(requests[0].url).to.contain('kvage=25;kvheight=3.42;kvtest=key'); + }); }); describe('Nexage api', () => { - let xhr; let requests; @@ -243,33 +332,61 @@ describe('AolAdapter', () => { it('should hit the nexage api endpoint with the nexage config', () => { adapter.callBids(createBidderRequest({ - params: { - dcn: '11223344', - pos: 'header-2324' - } + params: getNexageGetBidParams() })); - expect(requests[0].url).to.contain('hb.nexage.com/bidRequest?'); + + expect(requests[0].url).to.contain(NEXAGE_URL); }); it('should hit the nexage api custom endpoint if specified in the nexage config', () => { + let bidParams = Object.assign({ + host: 'qa-hb.nexage.com' + }, getNexageGetBidParams()); + adapter.callBids(createBidderRequest({ - params: { - host: 'qa-hb.nexage.com', - dcn: '11223344', - pos: 'header-2324' - } + params: bidParams })); expect(requests[0].url).to.contain('qa-hb.nexage.com/bidRequest?'); }); + it('should hit nexage api when nexage and marketplace params are present', () => { + let bidParams = Object.assign(getNexageGetBidParams(), getMarketplaceBidParams()); + + adapter.callBids(createBidderRequest({ + params: bidParams + })); + expect(requests[0].url).to.contain(NEXAGE_URL); + }); + + it('should hit nexage api via onemobile bidder code when nexage and marketplace params are present', () => { + let bidParams = Object.assign(getNexageGetBidParams(), getMarketplaceBidParams()); + + adapter.callBids(createBidderRequest({ + bids: [{ + bidder: 'onemobile' + }], + params: bidParams + })); + expect(requests[0].url).to.contain(NEXAGE_URL); + }); + + it('should not resolve endpoint for onemobile bidder code when only Marketplace params are present', () => { + adapter.callBids(createBidderRequest({ + bids: [{ + bidder: 'onemobile' + }], + params: getMarketplaceBidParams() + })); + + expect(requests.length).to.equal(0); + }); + it('should contain required params - dcn & pos', () => { adapter.callBids(createBidderRequest({ - params: { - dcn: '54321123', - pos: 'footer-2324' - } + params: getNexageGetBidParams() })); - expect(requests[0].url).to.contain('hb.nexage.com/bidRequest?dcn=54321123&pos=footer-2324'); + + expect(requests[0].url).to.contain(NEXAGE_URL + 'dcn=2c9d2b50015c5ce9db6aeeed8b9500d6&pos=header'); }); it('should contain cmd=bid by default', () => { @@ -300,38 +417,21 @@ describe('AolAdapter', () => { }); it('should hit the nexage api endpoint with post data with the openrtb config', () => { - let bidConfig = { - id: 'id-1', - imp: [{ - id: 'id-2', - banner: { - w: '100', - h: '100' - }, - tagid: 'header1' - }] - }; + let bidConfig = getNexagePostBidParams(); + adapter.callBids(createBidderRequest({ params: bidConfig })); - expect(requests[0].url).to.contain('hb.nexage.com/bidRequest?'); + expect(requests[0].url).to.contain(NEXAGE_URL); expect(requests[0].requestBody).to.deep.equal(bidConfig); expect(requests[0].requestHeaders).to.have.property('x-openrtb-version'); }); it('should not hit the nexage api endpoint with post data with the openrtb config' + ' if a required parameter is missing', () => { - let bidConfig = { - id: 'id-1', - imp: [{ - // id: 'id-2', - banner: { - w: '100', - h: '100' - }, - tagid: 'header1' - }] - }; + let bidConfig = getNexagePostBidParams(); + + bidConfig.imp[0].id = null; adapter.callBids(createBidderRequest({ params: bidConfig })); @@ -339,11 +439,9 @@ describe('AolAdapter', () => { }) ; }); - }); describe('bid response', () => { - let server; beforeEach(() => { @@ -470,8 +568,8 @@ describe('AolAdapter', () => { adapter.callBids(getDefaultBidRequest()); server.respond(); expect(bidmanager.addBidResponse.calledOnce).to.be.true; - var addedBidResponse = bidmanager.addBidResponse.firstCall.args[1]; - expect(addedBidResponse.ad).to.equal(""); + let addedBidResponse = bidmanager.addBidResponse.firstCall.args[1]; + expect(addedBidResponse.ad).to.equal(''); expect(addedBidResponse.cpm).to.equal(0.09); expect(addedBidResponse.width).to.equal(728); expect(addedBidResponse.height).to.equal(90); @@ -482,19 +580,19 @@ describe('AolAdapter', () => { it('should be added to bidmanager including pixels from pubapi response', () => { let bidResponse = getDefaultBidResponse(); bidResponse.ext = { - pixels: "" + pixels: '' }; server.respondWith(JSON.stringify(bidResponse)); adapter.callBids(getDefaultBidRequest()); server.respond(); expect(bidmanager.addBidResponse.calledOnce).to.be.true; - var addedBidResponse = bidmanager.addBidResponse.firstCall.args[1]; + let addedBidResponse = bidmanager.addBidResponse.firstCall.args[1]; expect(addedBidResponse.ad).to.equal( - "" + - "" + '' + + '' ); }); @@ -506,7 +604,7 @@ describe('AolAdapter', () => { adapter.callBids(getDefaultBidRequest()); server.respond(); expect(bidmanager.addBidResponse.calledOnce).to.be.true; - var addedBidResponse = bidmanager.addBidResponse.firstCall.args[1]; + let addedBidResponse = bidmanager.addBidResponse.firstCall.args[1]; expect(addedBidResponse.dealId).to.equal('12345'); }); @@ -525,7 +623,7 @@ describe('AolAdapter', () => { it('should not render pixels on pubapi response when no parameter is set', () => { let bidResponse = getDefaultBidResponse(); bidResponse.ext = { - pixels: "" + pixels: '' }; server.respondWith(JSON.stringify(bidResponse)); adapter.callBids(getDefaultBidRequest()); @@ -537,8 +635,8 @@ describe('AolAdapter', () => { it('should render pixels from pubapi response when param userSyncOn is set with \'bidResponse\'', () => { let bidResponse = getDefaultBidResponse(); bidResponse.ext = { - pixels: "" + pixels: '' }; server.respondWith(JSON.stringify(bidResponse)); @@ -566,8 +664,8 @@ describe('AolAdapter', () => { $$PREBID_GLOBAL$$.aolGlobals.pixelsDropped = true; let bidResponse = getDefaultBidResponse(); bidResponse.ext = { - pixels: "" + pixels: '' }; server.respondWith(JSON.stringify(bidResponse)); diff --git a/test/spec/unit/adapters/analytics/appnexus_spec.js b/test/spec/modules/appnexusAnalyticsAdapter_spec.js similarity index 93% rename from test/spec/unit/adapters/analytics/appnexus_spec.js rename to test/spec/modules/appnexusAnalyticsAdapter_spec.js index 4d241c2897c..7f68359de07 100644 --- a/test/spec/unit/adapters/analytics/appnexus_spec.js +++ b/test/spec/modules/appnexusAnalyticsAdapter_spec.js @@ -1,4 +1,4 @@ -import appnexusAnalytics from 'src/adapters/analytics/appnexus'; +import appnexusAnalytics from 'modules/appnexusAnalyticsAdapter'; import { assert } from 'chai'; import { getBidRequestedPayload } from 'test/fixtures/fixtures'; diff --git a/test/spec/adapters/appnexusAst_spec.js b/test/spec/modules/appnexusAstBidAdapter_spec.js similarity index 53% rename from test/spec/adapters/appnexusAst_spec.js rename to test/spec/modules/appnexusAstBidAdapter_spec.js index 273beac7629..0f125917614 100644 --- a/test/spec/adapters/appnexusAst_spec.js +++ b/test/spec/modules/appnexusAstBidAdapter_spec.js @@ -1,59 +1,59 @@ import { expect } from 'chai'; -import Adapter from 'src/adapters/appnexusAst'; +import Adapter from 'modules/appnexusAstBidAdapter'; import bidmanager from 'src/bidmanager'; -const ENDPOINT = '//ib.adnxs.com/ut/v2/prebid'; +const ENDPOINT = '//ib.adnxs.com/ut/v3/prebid'; const REQUEST = { - "bidderCode": "appnexusAst", - "requestId": "d3e07445-ab06-44c8-a9dd-5ef9af06d2a6", - "bidderRequestId": "7101db09af0db2", - "bids": [ + 'bidderCode': 'appnexusAst', + 'requestId': 'd3e07445-ab06-44c8-a9dd-5ef9af06d2a6', + 'bidderRequestId': '7101db09af0db2', + 'bids': [ { - "bidder": "appnexusAst", - "params": { - "placementId": "4799418", + 'bidder': 'appnexusAst', + 'params': { + 'placementId': '4799418', }, - "placementCode": "/19968336/header-bid-tag1", - "sizes": [ + 'placementCode': '/19968336/header-bid-tag1', + 'sizes': [ [728, 90], [970, 90] ], - "bidId": "84ab500420319d", - "bidderRequestId": "7101db09af0db2", - "requestId": "d3e07445-ab06-44c8-a9dd-5ef9af06d2a6" + 'bidId': '84ab500420319d', + 'bidderRequestId': '7101db09af0db2', + 'requestId': 'd3e07445-ab06-44c8-a9dd-5ef9af06d2a6' } ], - "start": 1469479810130 + 'start': 1469479810130 }; const RESPONSE = { - "version": "0.0.1", - "tags": [{ - "uuid": "84ab500420319d", - "tag_id": 4799418, - "auction_id": "2256922143947979797", - "no_ad_url": "http://lax1-ib.adnxs.com/no-ad", - "timeout_ms": 2500, - "ads": [{ - "content_source": "rtb", - "ad_type": "banner", - "buyer_member_id": 958, - "creative_id": 33989846, - "media_type_id": 1, - "media_subtype_id": 1, - "cpm": 0.500000, - "cpm_publisher_currency": 0.500000, - "publisher_currency_code": "$", - "client_initiated_ad_counting": true, - "rtb": { - "banner": { - "width": 728, - "height": 90, - "content": "" + 'version': '0.0.1', + 'tags': [{ + 'uuid': '84ab500420319d', + 'tag_id': 4799418, + 'auction_id': '2256922143947979797', + 'no_ad_url': 'http://lax1-ib.adnxs.com/no-ad', + 'timeout_ms': 2500, + 'ads': [{ + 'content_source': 'rtb', + 'ad_type': 'banner', + 'buyer_member_id': 958, + 'creative_id': 33989846, + 'media_type_id': 1, + 'media_subtype_id': 1, + 'cpm': 0.500000, + 'cpm_publisher_currency': 0.500000, + 'publisher_currency_code': '$', + 'client_initiated_ad_counting': true, + 'rtb': { + 'banner': { + 'width': 728, + 'height': 90, + 'content': '' }, - "trackers": [{ - "impression_urls": ["http://lax1-ib.adnxs.com/impression"] + 'trackers': [{ + 'impression_urls': ['http://lax1-ib.adnxs.com/impression'] }] } }] @@ -61,13 +61,11 @@ const RESPONSE = { }; describe('AppNexusAdapter', () => { - let adapter; beforeEach(() => adapter = Adapter.createNew()); describe('request function', () => { - let xhr; let requests; @@ -90,7 +88,7 @@ describe('AppNexusAdapter', () => { it('requires member && invCode', () => { let backup = REQUEST.bids[0].params; - REQUEST.bids[0].params = {member : 1234}; + REQUEST.bids[0].params = {member: 1234}; adapter.callBids(REQUEST); expect(requests).to.be.empty; REQUEST.bids[0].params = backup; @@ -131,6 +129,27 @@ describe('AppNexusAdapter', () => { delete REQUEST.bids[0].params.user; }); + it('attaches native params to the request', () => { + REQUEST.bids[0].mediaType = 'native'; + REQUEST.bids[0].nativeParams = { + title: {required: true}, + body: {required: true}, + sponsoredBy: {required: true} + }; + + adapter.callBids(REQUEST); + + const request = JSON.parse(requests[0].requestBody); + expect(request.tags[0].native.layouts[0]).to.deep.equal({ + title: {required: true}, + description: {required: true}, + sponsored_by: {required: true} + }); + + delete REQUEST.bids[0].mediaType; + delete REQUEST.bids[0].params.nativeParams; + }); + it('sends bid request to ENDPOINT via POST', () => { adapter.callBids(REQUEST); expect(requests[0].url).to.equal(ENDPOINT); @@ -143,7 +162,7 @@ describe('AppNexusAdapter', () => { singleArr: ['val'], singleArrNum: [5], multiValMixed: ['value1', 2, 'value3'], - singleValNum: 123, + singleValNum: 123, badValue: {'foo': 'bar'} // should be dropped }; @@ -151,29 +170,27 @@ describe('AppNexusAdapter', () => { const request = JSON.parse(requests[0].requestBody).tags[0]; expect(request.keywords).to.deep.equal([{ - "key": "single", - "value": ["val"] - }, { - "key": "singleArr", - "value": ["val"] - }, { - "key": "singleArrNum", - "value": ["5"] - }, { - "key": "multiValMixed", - "value": ["value1", "2", "value3"] - }, { - "key": "singleValNum", - "value": ["123"] - }]); + 'key': 'single', + 'value': ['val'] + }, { + 'key': 'singleArr', + 'value': ['val'] + }, { + 'key': 'singleArrNum', + 'value': ['5'] + }, { + 'key': 'multiValMixed', + 'value': ['value1', '2', 'value3'] + }, { + 'key': 'singleValNum', + 'value': ['123'] + }]); delete REQUEST.bids[0].params.keywords; }); - }); describe('response handler', () => { - let server; beforeEach(() => { @@ -200,12 +217,12 @@ describe('AppNexusAdapter', () => { it('handles nobid responses', () => { server.respondWith(JSON.stringify({ - "version": "0.0.1", - "tags": [{ - "uuid": "84ab500420319d", - "tag_id": 5976557, - "auction_id": "297492697822162468", - "nobid": true + 'version': '0.0.1', + 'tags': [{ + 'uuid': '84ab500420319d', + 'tag_id': 5976557, + 'auction_id': '297492697822162468', + 'nobid': true }] })); @@ -222,14 +239,14 @@ describe('AppNexusAdapter', () => { it('handles non-banner media responses', () => { server.respondWith(JSON.stringify({ - "tags": [{ - "uuid": "84ab500420319d", - "ads": [{ - "ad_type": "video", - "cpm": 0.500000, - "rtb": { - "video": { - "content": "" + 'tags': [{ + 'uuid': '84ab500420319d', + 'ads': [{ + 'ad_type': 'video', + 'cpm': 0.500000, + 'rtb': { + 'video': { + 'content': '' } } }] @@ -244,6 +261,45 @@ describe('AppNexusAdapter', () => { expect(response).to.have.property('statusMessage', 'Bid available'); }); + it('handles native responses', () => { + RESPONSE.tags[0].ads[0].ad_type = 'native'; + RESPONSE.tags[0].ads[0].rtb.native = { + 'title': 'Native Creative', + 'desc': 'Cool description great stuff', + 'sponsored': 'AppNexus', + 'icon': { + 'width': 0, + 'height': 0, + 'url': 'http://cdn.adnxs.com/icon.png' + }, + 'main_img': { + 'width': 2352, + 'height': 1516, + 'url': 'http://cdn.adnxs.com/img.png' + }, + 'link': { + 'url': 'https://www.appnexus.com', + 'fallback_url': '', + 'click_trackers': ['http://nym1-ib.adnxs.com/click'] + }, + 'impression_trackers': ['http://example.com'], + }; + + adapter.callBids(REQUEST); + server.respondWith(JSON.stringify(RESPONSE)); + server.respond(); + + sinon.assert.calledOnce(bidmanager.addBidResponse); + + const response = bidmanager.addBidResponse.firstCall.args[1]; + + expect(response.native.title).to.equal('Native Creative'); + expect(response.native.body).to.equal('Cool description great stuff'); + expect(response.native.image).to.equal('http://cdn.adnxs.com/img.png'); + + RESPONSE.tags[0].ads[0].ad_type = 'banner'; + }); + it('handles JSON.parse errors', () => { server.respondWith(''); @@ -257,7 +313,5 @@ describe('AppNexusAdapter', () => { 'Bid returned empty or error response' ); }); - }); - }); diff --git a/test/spec/adapters/appnexus_spec.js b/test/spec/modules/appnexusBidAdapter_spec.js similarity index 91% rename from test/spec/adapters/appnexus_spec.js rename to test/spec/modules/appnexusBidAdapter_spec.js index c29bd3dfdbe..e7f5310d90c 100644 --- a/test/spec/adapters/appnexus_spec.js +++ b/test/spec/modules/appnexusBidAdapter_spec.js @@ -1,10 +1,9 @@ import {expect} from 'chai'; -import Adapter from '../../../src/adapters/appnexus'; +import Adapter from '../../../modules/appnexusBidAdapter'; import bidManager from '../../../src/bidmanager'; import adLoader from '../../../src/adloader'; describe('AppNexus Adapter', () => { - let adapter; const REQUEST = { @@ -16,7 +15,7 @@ describe('AppNexus Adapter', () => { 'bidder': 'appnexus', 'params': { 'placementId': '4799418', - 'trafficSourceCode' : 'source' + 'trafficSourceCode': 'source' }, 'placementCode': '/19968336/header-bid-tag1', 'sizes': [ @@ -39,5 +38,4 @@ describe('AppNexus Adapter', () => { adapter.callBids(REQUEST); expect(adLoaderStub.getCall(0).args[0]).to.contain('traffic_source_code=source'); }); - }); diff --git a/test/spec/adapters/atomx_spec.js b/test/spec/modules/atomxBidAdapter_spec.js similarity index 94% rename from test/spec/adapters/atomx_spec.js rename to test/spec/modules/atomxBidAdapter_spec.js index fb4bdc83f1b..1a62bac28a1 100644 --- a/test/spec/adapters/atomx_spec.js +++ b/test/spec/modules/atomxBidAdapter_spec.js @@ -1,6 +1,5 @@ -window.pbjs = window.pbjs || {}; var chai = require('chai'); -var Adapter = require('src/adapters/atomx')(); +var Adapter = require('modules/atomxBidAdapter')(); var Ajax = require('src/ajax'); var adLoader = require('src/adloader'); var bidmanager = require('src/bidmanager.js'); @@ -14,7 +13,7 @@ describe('Atomx adapter', function () { bidId: 'bid_id', params: {id: 1234}, placementCode: 'ad-unit-1', - sizes: [[300, 250],[800, 600]] + sizes: [[300, 250], [800, 600]] } ] }; @@ -54,7 +53,7 @@ describe('Atomx adapter', function () { 'url': 'http://p.ato.mx/placement?id=1234', 'width': 300, 'height': 250, - 'code': 'ad-unit-1' + 'code': 'ad-unit-1' }); var responseEmpty = ''; @@ -65,7 +64,7 @@ describe('Atomx adapter', function () { }; describe('loads the tag code', function() { - var stubLoadScript = sinon.stub(adLoader, "loadScript"); + var stubLoadScript = sinon.stub(adLoader, 'loadScript'); Adapter.callBids(validData_1); sinon.assert.calledOnce(stubLoadScript); let url = stubLoadScript.firstCall.args[0]; @@ -95,7 +94,7 @@ describe('Atomx adapter', function () { it('ajax params should be matched', function () { Adapter.callBids(validData_1); sinon.assert.calledWith(stubAjax, sinon.match('/placement', function () { - }, validJsonParams, {method: "GET"})); + }, validJsonParams, {method: 'GET'})); }); }); describe('bid request with invalid data', function () { diff --git a/test/spec/adapters/audienceNetwork_spec.js b/test/spec/modules/audienceNetworkBidAdapter_spec.js similarity index 52% rename from test/spec/adapters/audienceNetwork_spec.js rename to test/spec/modules/audienceNetworkBidAdapter_spec.js index f1c528521b8..5cd064f169c 100644 --- a/test/spec/adapters/audienceNetwork_spec.js +++ b/test/spec/modules/audienceNetworkBidAdapter_spec.js @@ -7,11 +7,13 @@ import bidmanager from 'src/bidmanager'; import { STATUS } from 'src/constants.json'; import * as utils from 'src/utils'; -import AudienceNetwork from 'src/adapters/audienceNetwork'; +import AudienceNetwork from 'modules/audienceNetworkBidAdapter'; const bidderCode = 'audienceNetwork'; const placementId = 'test-placement-id'; const placementCode = '/test/placement/code'; +const playerwidth = 320; +const playerheight = 180; /** * Expect haystack string to contain needle n times. @@ -24,9 +26,7 @@ const expectToContain = (haystack, needle, n = 1) => expect(haystack.split(needle)).to.have.lengthOf(n + 1, `expected ${n} occurrence(s) of '${needle}' in '${haystack}'`); - describe('AudienceNetwork adapter', () => { - describe('Public API', () => { const adapter = AudienceNetwork(); it('getBidderCode', () => { @@ -42,7 +42,6 @@ describe('AudienceNetwork adapter', () => { }); describe('callBids parameter parsing', () => { - let xhr; let requests; let addBidResponse; @@ -99,14 +98,41 @@ describe('AudienceNetwork adapter', () => { expect(logError.calledOnce).to.equal(true); }); - it('valid parameters', () => { + it('filter valid sizes', () => { // Valid parameters const params = { bidderCode, bids: [{ bidder: bidderCode, params: { placementId }, - sizes: [[320, 50], [300, 250], '300x250', 'fullwidth', '320x50', 'native'] + sizes: [[1, 1], [300, 250]] + }] + }; + // Request bids + AudienceNetwork().callBids(params); + // Verify attempt to fetch response + expect(requests).to.have.lengthOf(1); + expect(requests[0].method).to.equal('GET'); + expect(requests[0].url) + .to.contain('https://an.facebook.com/v2/placementbid.json?') + .and.to.contain('placementids[]=test-placement-id') + .and.to.contain('adformats[]=300x250'); + // Verify no attempt to log error + expect(logError.called).to.equal(false); + }); + + it('valid parameters', () => { + const params = { + bidderCode, + bids: [{ + bidder: bidderCode, + params: { placementId }, + sizes: [[300, 250], [320, 50]] + }, + { + bidder: bidderCode, + params: { placementId }, + sizes: [[320, 50], [300, 250]] }] }; // Request bids @@ -114,31 +140,107 @@ describe('AudienceNetwork adapter', () => { // Verify attempt to fetch response expect(requests).to.have.lengthOf(1); expect(requests[0].method).to.equal('GET'); - expectToContain(requests[0].url, 'https://an.facebook.com/v2/placementbid.json?'); - expectToContain(requests[0].url, 'placementids[]=test-placement-id', 6); - expectToContain(requests[0].url, 'adformats[]=320x50', 2); - expectToContain(requests[0].url, 'adformats[]=300x250', 2); - expectToContain(requests[0].url, 'adformats[]=fullwidth'); - expectToContain(requests[0].url, 'adformats[]=native'); + expect(requests[0].url) + .to.contain('https://an.facebook.com/v2/placementbid.json?') + .and.to.contain('placementids[]=test-placement-id&placementids[]=test-placement-id') + .and.to.contain('adformats[]=320x50') + .and.to.contain('adformats[]=300x250'); // Verify no attempt to log error expect(logError.called).to.equal(false); }); + it('fullwidth', () => { + // Valid parameters + const params = { + bidderCode, + bids: [{ + bidder: bidderCode, + params: { + placementId, + format: 'fullwidth' + }, + sizes: [[300, 250]] + }] + }; + // Request bids + AudienceNetwork().callBids(params); + // Verify attempt to fetch response + expect(requests).to.have.lengthOf(1); + expect(requests[0].method).to.equal('GET'); + expect(requests[0].url) + .to.contain('https://an.facebook.com/v2/placementbid.json?') + .and.to.contain('placementids[]=test-placement-id') + .and.to.contain('adformats[]=fullwidth'); + // Verify no attempt to log error + expect(logError.called).to.equal(false); + }); + + it('native', () => { + // Valid parameters + const params = { + bidderCode, + bids: [{ + bidder: bidderCode, + params: { + placementId, + format: 'native' + }, + sizes: [[300, 250]] + }] + }; + // Request bids + AudienceNetwork().callBids(params); + // Verify attempt to fetch response + expect(requests).to.have.lengthOf(1); + expect(requests[0].method).to.equal('GET'); + expect(requests[0].url) + .to.contain('https://an.facebook.com/v2/placementbid.json?') + .and.to.contain('placementids[]=test-placement-id') + .and.to.contain('adformats[]=native'); + // Verify no attempt to log error + expect(logError.called).to.equal(false); + }); + + it('video', () => { + // Valid parameters + const params = { + bidderCode, + bids: [{ + bidder: bidderCode, + params: { + placementId, + format: 'video' + }, + sizes: [[playerwidth, playerheight]] + }] + }; + // Request bids + AudienceNetwork().callBids(params); + // Verify attempt to fetch response + expect(requests).to.have.lengthOf(1); + expect(requests[0].method).to.equal('GET'); + expect(requests[0].url) + .to.contain('https://an.facebook.com/v2/placementbid.json?') + .and.to.contain('placementids[]=test-placement-id') + .and.to.contain('adformats[]=video') + .and.to.contain('sdk[]='); + // Verify no attempt to log error + expect(logError.called).to.equal(false); + }); }); describe('callBids response handling', () => { - let server; let addBidResponse; let logError; - beforeEach( () => { + beforeEach(() => { server = sinon.fakeServer.create(); addBidResponse = sinon.stub(bidmanager, 'addBidResponse'); logError = sinon.stub(utils, 'logError'); }); - afterEach( () => { + afterEach(() => { server.restore(); bidmanager.addBidResponse.restore(); utils.logError.restore(); @@ -156,7 +258,7 @@ describe('AudienceNetwork adapter', () => { bids: [{ bidder: bidderCode, params: { placementId }, - sizes: ['native'] + sizes: [[300, 250]] }] }); server.respond(); @@ -190,8 +292,11 @@ describe('AudienceNetwork adapter', () => { bids: [{ bidder: bidderCode, placementCode, - params: { placementId }, - sizes: ['native'] + params: { + placementId, + format: 'native' + }, + sizes: [[300, 250]] }] }); server.respond(); @@ -204,11 +309,12 @@ describe('AudienceNetwork adapter', () => { expect(bidResponse.getStatusCode()).to.equal(STATUS.GOOD); expect(bidResponse.cpm).to.equal(1.23); expect(bidResponse.bidderCode).to.equal(bidderCode); - expect(bidResponse.width).to.equal(0); - expect(bidResponse.height).to.equal(0); - expect(bidResponse.ad).to.contain(`placementid:'${placementId}',format:'native',bidid:'test-bid-id'`, 'ad missing parameters'); - expect(bidResponse.ad).to.contain('getElementsByTagName("style")', 'ad missing native styles'); - expect(bidResponse.ad).to.contain('
', 'ad missing native container'); + expect(bidResponse.width).to.equal(300); + expect(bidResponse.height).to.equal(250); + expect(bidResponse.ad) + .to.contain(`placementid:'${placementId}',format:'native',bidid:'test-bid-id'`, 'ad missing parameters') + .and.to.contain('getElementsByTagName("style")', 'ad missing native styles') + .and.to.contain('
', 'ad missing native container'); // Verify Audience Network attributes in bid response expect(bidResponse.hb_bidder).to.equal('fan'); expect(bidResponse.fb_bidid).to.equal('test-bid-id'); @@ -239,7 +345,7 @@ describe('AudienceNetwork adapter', () => { bidder: bidderCode, placementCode, params: { placementId }, - sizes: ['300x250'] + sizes: [[300, 250]] }] }); server.respond(); @@ -254,9 +360,10 @@ describe('AudienceNetwork adapter', () => { expect(bidResponse.bidderCode).to.equal(bidderCode); expect(bidResponse.width).to.equal(300); expect(bidResponse.height).to.equal(250); - expect(bidResponse.ad).to.contain(`placementid:'${placementId}',format:'300x250',bidid:'test-bid-id'`, 'ad missing parameters'); - expect(bidResponse.ad).not.to.contain('getElementsByTagName("style")', 'ad should not contain native styles'); - expect(bidResponse.ad).not.to.contain('
', 'ad should not contain native container'); + expect(bidResponse.ad) + .to.contain(`placementid:'${placementId}',format:'300x250',bidid:'test-bid-id'`, 'ad missing parameters') + .and.not.to.contain('getElementsByTagName("style")', 'ad should not contain native styles') + .and.not.to.contain('
', 'ad should not contain native container'); // Verify no attempt to log error expect(logError.called).to.equal(false, 'logError called'); }); @@ -287,7 +394,7 @@ describe('AudienceNetwork adapter', () => { bidder: bidderCode, placementCode, params: { placementId }, - sizes: ['300x250'] + sizes: [[300, 250]] }] }); server.respond(); @@ -337,13 +444,16 @@ describe('AudienceNetwork adapter', () => { bids: [{ bidder: bidderCode, placementCode: placementCodeNative, - params: { placementId: placementIdNative }, - sizes: ['native'] + params: { + placementId: placementIdNative, + format: 'native' + }, + sizes: [[300, 250]] }, { bidder: bidderCode, placementCode: placementCodeIab, params: { placementId: placementIdIab }, - sizes: ['300x250'] + sizes: [[300, 250]] }] }); server.respond(); @@ -356,8 +466,8 @@ describe('AudienceNetwork adapter', () => { expect(addBidResponseNativeCall[1].getStatusCode()).to.equal(STATUS.GOOD); expect(addBidResponseNativeCall[1].cpm).to.equal(1.23); expect(addBidResponseNativeCall[1].bidderCode).to.equal(bidderCode); - expect(addBidResponseNativeCall[1].width).to.equal(0); - expect(addBidResponseNativeCall[1].height).to.equal(0); + expect(addBidResponseNativeCall[1].width).to.equal(300); + expect(addBidResponseNativeCall[1].height).to.equal(250); expect(addBidResponseNativeCall[1].ad).to.contain(`placementid:'${placementIdNative}',format:'native',bidid:'test-bid-id-native'`, 'ad missing parameters'); // Verify IAB const addBidResponseIabCall = addBidResponse.args[1]; @@ -373,6 +483,139 @@ describe('AudienceNetwork adapter', () => { expect(logError.called).to.equal(false, 'logError called'); }); - }); + it('valid video bid in response', () => { + const bidId = 'test-bid-id-video'; + // Valid response + server.respondWith(JSON.stringify({ + errors: [], + bids: { + [placementId]: [{ + placement_id: placementId, + bid_id: bidId, + bid_price_cents: 123, + bid_price_currency: 'usd', + bid_price_model: 'cpm' + }] + } + })); + // Request bids + AudienceNetwork().callBids({ + bidderCode, + bids: [{ + bidder: bidderCode, + placementCode, + params: { + placementId, + format: 'video' + }, + sizes: [[playerwidth, playerheight]] + }] + }); + server.respond(); + // Verify addBidResponse call + expect(addBidResponse.calledOnce).to.equal(true); + const addBidResponseArgs = addBidResponse.args[0]; + expect(addBidResponseArgs).to.have.lengthOf(2); + expect(addBidResponseArgs[0]).to.equal(placementCode); + expect(addBidResponseArgs[1].getStatusCode()).to.equal(STATUS.GOOD); + expect(addBidResponseArgs[1].cpm).to.equal(1.23); + expect(addBidResponseArgs[1].bidderCode).to.equal(bidderCode); + // Video-specific properties + expect(addBidResponseArgs[1].mediaType).to.equal('video'); + expect(addBidResponseArgs[1].vastUrl) + .to.equal(addBidResponseArgs[1].descriptionUrl) + .and.to.contain('https://an.facebook.com/v1/instream/vast.xml?') + .and.to.contain(`placementid=${placementId}`) + .and.to.contain('pageurl=http%3A%2F%2F') + .and.to.contain(`playerwidth=${playerwidth}`) + .and.to.contain(`playerheight=${playerheight}`) + .and.to.contain(`bidid=${bidId}`); + expect(addBidResponseArgs[1].width).to.equal(playerwidth); + expect(addBidResponseArgs[1].height).to.equal(playerheight); + // Verify no attempt to log error + expect(logError.called).to.equal(false, 'logError called'); + }); + it('mixed video and native bids', () => { + const videoPlacementId = 'test-video-placement-id'; + const videoBidId = 'test-video-bid-id'; + const nativePlacementId = 'test-native-placement-id'; + const nativeBidId = 'test-native-bid-id'; + // Valid response + server.respondWith(JSON.stringify({ + errors: [], + bids: { + [videoPlacementId]: [{ + placement_id: videoPlacementId, + bid_id: videoBidId, + bid_price_cents: 123, + bid_price_currency: 'usd', + bid_price_model: 'cpm' + }], + [nativePlacementId]: [{ + placement_id: nativePlacementId, + bid_id: nativeBidId, + bid_price_cents: 456, + bid_price_currency: 'usd', + bid_price_model: 'cpm' + }] + } + })); + // Request bids + AudienceNetwork().callBids({ + bidderCode, + bids: [{ + bidder: bidderCode, + placementCode, + params: { + placementId: videoPlacementId, + format: 'video' + }, + sizes: [[playerwidth, playerheight]] + }, { + bidder: bidderCode, + placementCode, + params: { + placementId: nativePlacementId, + format: 'native' + }, + sizes: [[300, 250]] + }] + }); + server.respond(); + // Verify multiple attempts to call addBidResponse + expect(addBidResponse.calledTwice).to.equal(true); + // Verify video + const addBidResponseVideoCall = addBidResponse.args[0]; + expect(addBidResponseVideoCall).to.have.lengthOf(2); + expect(addBidResponseVideoCall[0]).to.equal(placementCode); + expect(addBidResponseVideoCall[1].getStatusCode()).to.equal(STATUS.GOOD); + expect(addBidResponseVideoCall[1].cpm).to.equal(1.23); + expect(addBidResponseVideoCall[1].bidderCode).to.equal(bidderCode); + // Video-specific properties + expect(addBidResponseVideoCall[1].mediaType).to.equal('video'); + expect(addBidResponseVideoCall[1].vastUrl) + .to.equal(addBidResponseVideoCall[1].descriptionUrl) + .and.to.contain('https://an.facebook.com/v1/instream/vast.xml?') + .and.to.contain(`placementid=${videoPlacementId}`) + .and.to.contain('pageurl=http%3A%2F%2F') + .and.to.contain(`playerwidth=${playerwidth}`) + .and.to.contain(`playerheight=${playerheight}`) + .and.to.contain(`bidid=${videoBidId}`); + expect(addBidResponseVideoCall[1].width).to.equal(playerwidth); + expect(addBidResponseVideoCall[1].height).to.equal(playerheight); + // Verify native + const addBidResponseNativeCall = addBidResponse.args[1]; + expect(addBidResponseNativeCall).to.have.lengthOf(2); + expect(addBidResponseNativeCall[0]).to.equal(placementCode); + expect(addBidResponseNativeCall[1].getStatusCode()).to.equal(STATUS.GOOD); + expect(addBidResponseNativeCall[1].cpm).to.equal(4.56); + expect(addBidResponseNativeCall[1].bidderCode).to.equal(bidderCode); + expect(addBidResponseNativeCall[1].width).to.equal(300); + expect(addBidResponseNativeCall[1].height).to.equal(250); + expect(addBidResponseNativeCall[1].ad).to.contain(`placementid:'${nativePlacementId}',format:'native',bidid:'${nativeBidId}'`); + // Verify no attempt to log error + expect(logError.called).to.equal(false, 'logError called'); + }); + }); }); diff --git a/test/spec/modules/beachfrontBidAdapter_spec.js b/test/spec/modules/beachfrontBidAdapter_spec.js new file mode 100644 index 00000000000..0b0f868f108 --- /dev/null +++ b/test/spec/modules/beachfrontBidAdapter_spec.js @@ -0,0 +1,131 @@ +import { expect } from 'chai'; +import BeachfrontAdapter from 'modules/beachfrontBidAdapter'; +import bidmanager from 'src/bidmanager'; + +const ENDPOINT = '//reachms.bfmio.com/bid.json?exchange_id=11bc5dd5-7421-4dd8-c926-40fa653bec76'; + +const REQUEST = { + 'width': 640, + 'height': 480, + 'bidId': '2a1444be20bb2c', + 'bidder': 'beachfront', + 'bidderRequestId': '7101db09af0db2', + 'params': { + 'appId': 'whatever', + 'video': {}, + 'placementCode': 'video', + 'sizes': [ + 640, 480 + ] + }, + 'bids': [ + { + 'bidFloor': 0.01, + 'bidder': 'beachfront', + 'params': { + 'appId': '11bc5dd5-7421-4dd8-c926-40fa653bec76', + 'bidfloor': 0.01, + 'dev': true + }, + 'placementCode': 'video', + 'sizes': [640, 480], + 'bidId': '2a1444be20bb2c', + 'bidderRequestId': '7101db09af0db2', + 'requestId': '979b659e-ecff-46b8-ae03-7251bae4b725' + } + ], + 'requestId': '979b659e-ecff-46b8-ae03-7251bae4b725', +}; +var RESPONSE = { + 'bidPrice': 5.00, + 'url': 'http://reachms.bfmio.com/getmu?aid=bid:19c4a196-fb21-4c81-9a1a-ecc5437a39da:0a47f4ce-d91f-48d0-bd1c-64fa2c196f13:2.90&dsp=58bf26882aba5e6ad608beda,0.612&i_type=pre' +}; + +describe('BeachfrontAdapter', () => { + let adapter; + + beforeEach(() => adapter = BeachfrontAdapter.createNew()); + + describe('request function', () => { + let xhr; + let requests; + beforeEach(() => { + xhr = sinon.useFakeXMLHttpRequest(); + requests = []; + xhr.onCreate = request => requests.push(request); + }); + + afterEach(() => xhr.restore()); + + it('exists and is a function', () => { + expect(adapter.callBids).to.exist.and.to.be.a('function'); + }); + + it('requires parameters to make request', () => { + adapter.callBids({}); + expect(requests).to.be.empty; + }); + + it('sends bid request to ENDPOINT via POST', () => { + adapter.callBids(REQUEST); + expect(requests[0].url).to.equal(ENDPOINT); + expect(requests[0].method).to.equal('POST'); + }); + }); + + describe('response handler', () => { + let server; + + beforeEach(() => { + server = sinon.fakeServer.create(); + sinon.stub(bidmanager, 'addBidResponse'); + }); + + afterEach(() => { + server.restore(); + bidmanager.addBidResponse.restore(); + }); + + it('registers bids', () => { + server.respondWith(JSON.stringify(RESPONSE)); + + adapter.callBids(REQUEST); + server.respond(); + sinon.assert.calledOnce(bidmanager.addBidResponse); + + const response = bidmanager.addBidResponse.firstCall.args[1]; + expect(response).to.have.property('statusMessage', 'Bid available'); + expect(response).to.have.property('cpm', 5.00); + }); + + it('handles nobid responses', () => { + server.respondWith(JSON.stringify({ + 'bidPrice': 5.00 + })); + + adapter.callBids(REQUEST); + server.respond(); + sinon.assert.calledOnce(bidmanager.addBidResponse); + + const response = bidmanager.addBidResponse.firstCall.args[1]; + expect(response).to.have.property( + 'statusMessage', + 'Bid returned empty or error response' + ); + }); + + it('handles JSON.parse errors', () => { + server.respondWith(''); + + adapter.callBids(REQUEST); + server.respond(); + sinon.assert.calledOnce(bidmanager.addBidResponse); + + const response = bidmanager.addBidResponse.firstCall.args[1]; + expect(response).to.have.property( + 'statusMessage', + 'Bid returned empty or error response' + ); + }); + }); +}); diff --git a/test/spec/modules/bidfluenceBidAdapter_spec.js b/test/spec/modules/bidfluenceBidAdapter_spec.js new file mode 100644 index 00000000000..f623954fa9f --- /dev/null +++ b/test/spec/modules/bidfluenceBidAdapter_spec.js @@ -0,0 +1,71 @@ +describe('Bidfluence Adapter', () => { + const expect = require('chai').expect; + const adapter = require('modules/bidfluenceBidAdapter'); + const bidmanager = require('src/bidmanager'); + + var REQUEST = { + bidderCode: 'bidfluence', + sizes: [[300, 250]], + placementCode: 'div-1', + bids: [{ + bidder: 'bidfluence', + params: { + pubId: 'test', + adunitId: 'test' + } + }] + }; + + var RESPONSE = { + ad: 'ad-code', + cpm: 0.9, + width: 300, + height: 250, + placementCode: 'div-1' + }; + + var NO_RESPONSE = { + ad: 'ad-code', + cpm: 0, + width: 300, + height: 250, + placementCode: 'div-1' + }; + + it('Should exist and be a function', function () { + expect($$PREBID_GLOBAL$$.bfPbjsCB).to.exist.and.to.be.a('function'); + }); + + it('Shoud push a valid bid', () => { + var stubAddBidResponse = sinon.stub(bidmanager, 'addBidResponse'); + $$PREBID_GLOBAL$$._bidsRequested.push(REQUEST); + adapter(); + $$PREBID_GLOBAL$$.bfPbjsCB(RESPONSE); + + var bidPlacementCode1 = stubAddBidResponse.getCall(0).args[0]; + var bidObject1 = stubAddBidResponse.getCall(0).args[1]; + + expect(bidPlacementCode1).to.equal('div-1'); + expect(bidObject1.getStatusCode()).to.equal(1); + expect(bidObject1.bidderCode).to.equal('bidfluence'); + + stubAddBidResponse.restore(); + }); + + it('Shoud push an empty bid', () => { + var stubAddBidResponse = sinon.stub(bidmanager, 'addBidResponse'); + $$PREBID_GLOBAL$$._bidsRequested.push(REQUEST); + adapter(); + + $$PREBID_GLOBAL$$.bfPbjsCB(NO_RESPONSE); + + var bidPlacementCode1 = stubAddBidResponse.getCall(0).args[0]; + var bidObject1 = stubAddBidResponse.getCall(0).args[1]; + + expect(bidPlacementCode1).to.equal('div-1'); + expect(bidObject1.getStatusCode()).to.equal(2); + expect(bidObject1.bidderCode).to.equal('bidfluence'); + + stubAddBidResponse.restore(); + }); +}); diff --git a/test/spec/modules/carambolaBidAdapter_spec.js b/test/spec/modules/carambolaBidAdapter_spec.js new file mode 100644 index 00000000000..660944b4f28 --- /dev/null +++ b/test/spec/modules/carambolaBidAdapter_spec.js @@ -0,0 +1,139 @@ +import {expect} from 'chai'; +import * as utils from 'src/utils'; +import CarambolaAdapter from 'modules/carambolaBidAdapter'; +import bidmanager from 'src/bidmanager'; + +const DEFAULT_BIDDER_REQUEST = { + bidderCode: 'carambola', + requestId: 'c9ad932a-41d9-4821-b6dc-0c8146029faf', + adId: '2e3daacdeed03d', + start: new Date().getTime(), + bids: [{ + bidder: 'carambola', + adId: '2e3daacdeed03d', + requestId: 'c9ad932a-41d9-4821-b6dc-0c8146029faf', + adUnitCode: 'cbola_prebid_code_97', + token: 'CGYCLyIy', + pageViewId: '22478638', + params: { + pid: 'hbtest', + did: 112591, + wid: 0 + } + }] +}; + +const DEFAULT_HB_RESPONSE = { + cpm: 0.1693953107111156, + ad: ' ', + token: '9cd6bf9c-433d-4663-b67f-da727f4cebff', + width: '300', + height: '250', + currencyCode: 'USD', + pageViewId: '22478638', + requestStatus: 1 + +}; + +describe('carambolaAdapter', function () { + let adapter; + + beforeEach(() => adapter = new CarambolaAdapter()); + + function createBidderRequest({bids, params} = {}) { + var bidderRequest = utils.cloneJson(DEFAULT_BIDDER_REQUEST); + if (bids && Array.isArray(bids)) { + bidderRequest.bids = bids; + } + if (params) { + bidderRequest.bids.forEach(bid => bid.params = params); + } + return bidderRequest; + } + + describe('callBids()', () => { + it('exists and is a function', () => { + expect(adapter.callBids).to.exist.and.to.be.a('function'); + }); + + // bid request starts + describe('bid request', () => { + let xhr; + let requests; + + beforeEach(() => { + xhr = sinon.useFakeXMLHttpRequest(); + requests = []; + xhr.onCreate = request => requests.push(request); + }); + + afterEach(() => xhr.restore()); + + it('requires parameters to be made', () => { + adapter.callBids({}); + expect(requests[0]).to.be.empty; + }); + + it('should hit the default route.carambo.la endpoint', () => { + adapter.callBids(DEFAULT_BIDDER_REQUEST); + expect(requests[0].url).to.contain('route.carambo.la'); + }); + + it('should verifiy that a page_view_id is sent', () => { + adapter.callBids(DEFAULT_BIDDER_REQUEST); + expect(requests[0].url).to.contain('pageViewId='); + }); + + it('should should send the correct did', () => { + adapter.callBids(createBidderRequest({ + params: { + did: 112591, + wid: 0 + } + })); + expect(requests[0].url).to.contain('did=112591'); + }); + }); + // bid request ends + + // bid response starts + describe('bid response', () => { + let server; + + beforeEach(() => { + server = sinon.fakeServer.create(); + sinon.stub(bidmanager, 'addBidResponse'); + }); + + afterEach(() => { + server.restore(); + bidmanager.addBidResponse.restore(); + }); + + it('should be added to bidmanager if response is valid', () => { + server.respondWith(JSON.stringify(DEFAULT_HB_RESPONSE)); + adapter.callBids(DEFAULT_BIDDER_REQUEST); + server.respond(); + expect(bidmanager.addBidResponse.calledOnce).to.be.true; + }); + + it('should be added to bidmanager with correct bidderCode', () => { + server.respondWith(JSON.stringify(DEFAULT_HB_RESPONSE)); + adapter.callBids(DEFAULT_BIDDER_REQUEST); + server.respond(); + expect(bidmanager.addBidResponse.calledOnce).to.be.true; + expect(bidmanager.addBidResponse.firstCall.args[1]).to.have.property('bidderCode', 'carambola'); + }); + + it('should have pageViewId matching the pageViewId from related bid request', () => { + server.respondWith(JSON.stringify(DEFAULT_HB_RESPONSE)); + adapter.callBids(DEFAULT_BIDDER_REQUEST); + server.respond(); + expect(bidmanager.addBidResponse.calledOnce).to.be.true; + expect(bidmanager.addBidResponse.firstCall.args[1]) + .to.have.property('pvid', DEFAULT_BIDDER_REQUEST.bids[0].pageViewId); + }); + }); + // bid response ends + }); +}); diff --git a/test/spec/modules/centroBidAdapter_spec.js b/test/spec/modules/centroBidAdapter_spec.js new file mode 100644 index 00000000000..9f354e1ba56 --- /dev/null +++ b/test/spec/modules/centroBidAdapter_spec.js @@ -0,0 +1,218 @@ +describe('centro adapter tests', function () { + var expect = require('chai').expect; + var assert = require('chai').assert; + var urlParse = require('url-parse'); + var querystringify = require('querystringify'); + + var adapter = require('modules/centroBidAdapter'); + var bidmanager = require('src/bidmanager'); + var adLoader = require('src/adloader'); + var utils = require('src/utils'); + + let stubLoadScript; + beforeEach(function () { + stubLoadScript = sinon.stub(adLoader, 'loadScript'); + }); + + afterEach(function () { + stubLoadScript.restore(); + }); + + var logErrorSpy; + beforeEach(function () { + logErrorSpy = sinon.spy(utils, 'logError'); + }); + + afterEach(function () { + logErrorSpy.restore(); + }); + + describe('creation of bid url', function () { + if (typeof ($$PREBID_GLOBAL$$._bidsRequested) === 'undefined') { + $$PREBID_GLOBAL$$._bidsRequested = []; + } + + it('should fix parameter name', function () { + var params = { + bidderCode: 'centro', + bids: [ + { + bidder: 'centro', + sizes: [[300, 250]], + params: { + unit: 28136, + page_url: 'http://test_url.ru' + }, + placementCode: 'div-gpt-ad-12345-1' + }, + { + bidder: 'centro', + sizes: [[728, 90]], + params: { + unit: 28137 + }, + placementCode: 'div-gpt-ad-12345-2' + }, + { + bidder: 'centro', + sizes: [[728, 90]], + params: {}, + placementCode: 'div-gpt-ad-12345-3' + } + ] + }; + + adapter().callBids(params); + var bidUrl1 = stubLoadScript.getCall(0).args[0]; + var bidUrl2 = stubLoadScript.getCall(1).args[0]; + + sinon.assert.calledWith(logErrorSpy, 'Bid has no unit', 'centro'); + sinon.assert.calledWith(stubLoadScript, bidUrl1); + + var parsedBidUrl = urlParse(bidUrl1); + var parsedBidUrlQueryString = querystringify.parse(parsedBidUrl.query); + var generatedCallback = 'window["adCentroHandler_28136300x250div-gpt-ad-12345-1"]'; + + expect(parsedBidUrl.hostname).to.equal('staging.brand-server.com'); + expect(parsedBidUrl.pathname).to.equal('/hb'); + + expect(parsedBidUrlQueryString).to.have.property('s').and.to.equal('28136'); + expect(parsedBidUrlQueryString).to.have.property('url').and.to.equal('http://test_url.ru'); + expect(parsedBidUrlQueryString).to.have.property('sz').and.to.equal('300x250'); + expect(parsedBidUrlQueryString).to.have.property('callback').and.to.equal(generatedCallback); + + sinon.assert.calledWith(stubLoadScript, bidUrl2); + + parsedBidUrl = urlParse(bidUrl2); + parsedBidUrlQueryString = querystringify.parse(parsedBidUrl.query); + generatedCallback = 'window["adCentroHandler_28137728x90div-gpt-ad-12345-2"]'; + + expect(parsedBidUrl.hostname).to.equal('t.brand-server.com'); + expect(parsedBidUrl.pathname).to.equal('/hb'); + + expect(parsedBidUrlQueryString).to.have.property('s').and.to.equal('28137'); + expect(parsedBidUrlQueryString).to.have.property('url').and.to.equal(location.href); + expect(parsedBidUrlQueryString).to.have.property('sz').and.to.equal('728x90'); + expect(parsedBidUrlQueryString).to.have.property('callback').and.to.equal(generatedCallback); + }); + }); + + describe('handling of the callback response', function () { + if (typeof ($$PREBID_GLOBAL$$._bidsReceived) === 'undefined') { + $$PREBID_GLOBAL$$._bidsReceived = []; + } + if (typeof ($$PREBID_GLOBAL$$._bidsRequested) === 'undefined') { + $$PREBID_GLOBAL$$._bidsRequested = []; + } + if (typeof ($$PREBID_GLOBAL$$._adsReceived) === 'undefined') { + $$PREBID_GLOBAL$$._adsReceived = []; + } + + var params = { + bidderCode: 'centro', + bids: [ + { + bidder: 'centro', + sizes: [[300, 250]], + params: { + unit: 28136 + }, + placementCode: '/19968336/header-bid-tag-0' + }, + { + bidder: 'centro', + sizes: [[728, 90]], + params: { + unit: 111111 + }, + placementCode: '/19968336/header-bid-tag-1' + }, + { + bidder: 'centro', + sizes: [[728, 90]], + params: { + unit: 222222 + }, + placementCode: '/19968336/header-bid-tag-2' + }, + { + bidder: 'centro', + sizes: [[728, 90]], + params: { + unit: 333333 + }, + placementCode: '/19968336/header-bid-tag-3' + } + ] + }; + + it('callback function should exist', function () { + adapter().callBids(params); + + expect(window['adCentroHandler_28136300x250%2F19968336%2Fheader-bid-tag-0']) + .to.exist.and.to.be.a('function'); + expect(window['adCentroHandler_111111728x90%2F19968336%2Fheader-bid-tag-1']) + .to.exist.and.to.be.a('function'); + }); + + it('bidmanager.addBidResponse should be called with correct arguments', function () { + var stubAddBidResponse = sinon.stub(bidmanager, 'addBidResponse'); + + adapter().callBids(params); + + var adUnits = new Array(); + var unit = new Object(); + unit.bids = params.bids; + unit.code = '/19968336/header-bid-tag'; + unit.sizes = [[300, 250], [728, 90]]; + adUnits.push(unit); + + if (typeof ($$PREBID_GLOBAL$$._bidsRequested) === 'undefined') { + $$PREBID_GLOBAL$$._bidsRequested = [params]; + } else { + $$PREBID_GLOBAL$$._bidsRequested.push(params); + } + + $$PREBID_GLOBAL$$.adUnits = adUnits; + + var response = {'adTag': '
test content
', 'statusMessage': 'Bid available', 'height': 250, '_comment': '', 'value': 0.2, 'width': 300, 'sectionID': 28136}; + var response2 = {'adTag': '', 'statusMessage': 'No bid', 'height': 0, 'value': 0, 'width': 0, 'sectionID': 111111}; + var response3 = {'adTag': '', 'height': 0, 'value': 0, 'width': 0, 'sectionID': 222222}; + var response4 = ''; + + window['adCentroHandler_28136300x250%2F19968336%2Fheader-bid-tag-0'](response); + window['adCentroHandler_111111728x90%2F19968336%2Fheader-bid-tag-1'](response2); + window['adCentroHandler_222222728x90%2F19968336%2Fheader-bid-tag-2'](response3); + window['adCentroHandler_333333728x90%2F19968336%2Fheader-bid-tag-3'](response4); + + var bidPlacementCode1 = stubAddBidResponse.getCall(0).args[0]; + var bidObject1 = stubAddBidResponse.getCall(0).args[1]; + var bidPlacementCode2 = stubAddBidResponse.getCall(1).args[0]; + var bidObject2 = stubAddBidResponse.getCall(1).args[1]; + var bidPlacementCode3 = stubAddBidResponse.getCall(2).args[0]; + var bidObject3 = stubAddBidResponse.getCall(2).args[1]; + var bidPlacementCode4 = stubAddBidResponse.getCall(3).args[0]; + var bidObject4 = stubAddBidResponse.getCall(3).args[1]; + + expect(logErrorSpy.getCall(0).args[0]).to.equal('Requested unit is 222222. Bid has missmatch format.'); + expect(logErrorSpy.getCall(1).args[0]).to.equal('Requested unit is 333333. Response has no bid.'); + + expect(bidPlacementCode1).to.equal('/19968336/header-bid-tag-0'); + expect(bidObject1.cpm).to.equal(0.2); + expect(bidObject1.ad).to.equal('
test content
'); + expect(bidObject1.width).to.equal(300); + expect(bidObject1.height).to.equal(250); + expect(bidObject1.getStatusCode()).to.equal(1); + expect(bidObject1.bidderCode).to.equal('centro'); + + expect(bidPlacementCode2).to.equal('/19968336/header-bid-tag-1'); + expect(bidObject2.getStatusCode()).to.equal(2); + expect(bidPlacementCode3).to.equal('/19968336/header-bid-tag-2'); + expect(bidObject3.getStatusCode()).to.equal(2); + expect(bidPlacementCode4).to.equal('/19968336/header-bid-tag-3'); + expect(bidObject4.getStatusCode()).to.equal(2); + + stubAddBidResponse.restore(); + }); + }); +}); diff --git a/test/spec/adapters/conversant_spec.js b/test/spec/modules/conversantBidAdapter_spec.js similarity index 60% rename from test/spec/adapters/conversant_spec.js rename to test/spec/modules/conversantBidAdapter_spec.js index dead09688ba..57cd9411e66 100644 --- a/test/spec/adapters/conversant_spec.js +++ b/test/spec/modules/conversantBidAdapter_spec.js @@ -1,9 +1,8 @@ var expect = require('chai').expect; -var Adapter = require('src/adapters/conversant'); +var Adapter = require('modules/conversantBidAdapter'); var bidManager = require('src/bidmanager'); describe('Conversant adapter tests', function () { - var addBidResponseSpy; var adapter; @@ -17,10 +16,11 @@ describe('Conversant adapter tests', function () { sizes: [[300, 600]], params: { site_id: '87293', + position: 1, + tag_id: 'tagid-1', secure: false } - }, - { + }, { bidId: 'bidId2', bidder: 'conversant', placementCode: 'div2', @@ -29,21 +29,33 @@ describe('Conversant adapter tests', function () { site_id: '87293', secure: false } - }, - { + }, { bidId: 'bidId3', bidder: 'conversant', placementCode: 'div3', sizes: [[300, 600], [160, 600]], params: { site_id: '87293', + position: 1, + tag_id: '', + secure: false + } + }, { + bidId: 'bidId4', + bidder: 'conversant', + placementCode: 'div4', + mediaType: 'video', + sizes: [[480, 480]], + params: { + site_id: '89192', + pos: 1, + tagid: 'tagid-4', secure: false } } ] }; - it('The Conversant response should exist and be a function', function () { expect($$PREBID_GLOBAL$$.conversantResponse).to.exist.and.to.be.a('function'); }); @@ -67,14 +79,14 @@ describe('Conversant adapter tests', function () { id: 1111111, impid: 'bidId1', price: 0 - },{ + }, { id: 2345, impid: 'bidId2', price: 0.22, nurl: '', adm: 'adm2', - h:300, - w:600 + h: 300, + w: 600 }] }] }; @@ -103,7 +115,7 @@ describe('Conversant adapter tests', function () { expect(thirdBid.bidderCode).to.equal('conversant'); expect(placementCode3).to.equal('div3'); - expect(addBidResponseSpy.getCalls().length).to.equal(3); + expect(addBidResponseSpy.getCalls().length).to.equal(4); }); it('Should submit bids with statuses of 2 to the bid manager for empty bid responses', function () { @@ -128,7 +140,7 @@ describe('Conversant adapter tests', function () { expect(thirdBid.getStatusCode()).to.equal(2); expect(thirdBid.bidderCode).to.equal('conversant'); - expect(addBidResponseSpy.getCalls().length).to.equal(3); + expect(addBidResponseSpy.getCalls().length).to.equal(4); }); it('Should submit valid bids to the bid manager', function () { @@ -139,29 +151,28 @@ describe('Conversant adapter tests', function () { id: 1111111, impid: 'bidId1', price: 0.11, - nurl : '', + nurl: '', adm: 'adm', h: 250, w: 300, - ext : {} - },{ + ext: {} + }, { id: 2345, impid: 'bidId2', price: 0.22, nurl: '', adm: 'adm2', - h:300, - w:600 - }, - { - id: 33333, - impid: 'bidId3', - price: 0.33, - nurl: '', - adm: 'adm3', - h: 160, - w: 600 - }] + h: 300, + w: 600 + }, { + id: 33333, + impid: 'bidId3', + price: 0.33, + nurl: '', + adm: 'adm3', + h: 160, + w: 600 + }] }] }; @@ -177,7 +188,7 @@ describe('Conversant adapter tests', function () { expect(firstBid.getStatusCode()).to.equal(1); expect(firstBid.bidderCode).to.equal('conversant'); expect(firstBid.cpm).to.equal(0.11); - expect(firstBid.ad).to.equal('adm'+ ''); + expect(firstBid.ad).to.equal('adm' + ''); expect(placementCode1).to.equal('div1'); expect(secondBid.getStatusCode()).to.equal(1); @@ -192,14 +203,39 @@ describe('Conversant adapter tests', function () { expect(thirdBid.ad).to.equal('adm3' + ''); expect(placementCode3).to.equal('div3'); - expect(addBidResponseSpy.getCalls().length).to.equal(3); + expect(addBidResponseSpy.getCalls().length).to.equal(4); }); - }); + it('Should submit video bid responses correctly.', function () { + var bidResponse = { + id: 123, + seatbid: [{ + bid: [{ + id: 1111111, + impid: 'bidId4', + price: 0.11, + nurl: 'imp_tracker', + adm: 'vasturl' + }] + }] + }; + + $$PREBID_GLOBAL$$.conversantResponse(bidResponse); + + var videoBid = addBidResponseSpy.getCall(0).args[1]; + var placementCode = addBidResponseSpy.getCall(0).args[0]; + + expect(videoBid.getStatusCode()).to.equal(1); + expect(videoBid.bidderCode).to.equal('conversant'); + expect(videoBid.cpm).to.equal(0.11); + expect(videoBid.vastUrl).to.equal('vasturl'); + expect(placementCode).to.equal('div4'); + }) + }); describe('Should submit the correct headers in the xhr', function () { var server, - adapter; + adapter; var bidResponse = { id: 123, @@ -208,29 +244,28 @@ describe('Conversant adapter tests', function () { id: 1111, impid: 'bidId1', price: 0.11, - nurl : '', + nurl: '', adm: 'adm', h: 250, w: 300, - ext : {} - },{ + ext: {} + }, { id: 2222, impid: 'bidId2', price: 0.22, nurl: '', adm: 'adm2', - h:300, - w:600 - }, - { - id: 3333, - impid: 'bidId3', - price: 0.33, - nurl: '', - adm: 'adm3', - h: 160, - w: 600 - }] + h: 300, + w: 600 + }, { + id: 3333, + impid: 'bidId3', + price: 0.33, + nurl: '', + adm: 'adm3', + h: 160, + w: 600 + }] }] }; @@ -256,4 +291,86 @@ describe('Conversant adapter tests', function () { expect(request.requestBody).to.not.be.empty; }); }); + describe('Should create valid bid requests.', function () { + var server, + adapter; + + var bidResponse = { + id: 123, + seatbid: [{ + bid: [{ + id: 1111, + impid: 'bidId1', + price: 0.11, + nurl: '', + adm: 'adm', + h: 250, + w: 300, + ext: {} + }, { + id: 2222, + impid: 'bidId2', + price: 0.22, + nurl: '', + adm: 'adm2', + h: 300, + w: 600 + }, { + id: 3333, + impid: 'bidId3', + price: 0.33, + nurl: '', + adm: 'adm3', + h: 160, + w: 600 + }] + }] + }; + + beforeEach(function () { + server = sinon.fakeServer.create(); + adapter = new Adapter(); + }); + + afterEach(function () { + server.restore(); + }); + + beforeEach(function () { + var resp = [200, {'Content-type': 'text/javascript'}, '$$PREBID_GLOBAL$$.conversantResponse(\'' + JSON.stringify(bidResponse) + '\')']; + server.respondWith('POST', new RegExp('media.msg.dotomi.com/s2s/header'), resp); + }); + + it('Should create valid bid requests.', function () { + adapter.callBids(bidderRequest); + server.respond(); + var request = JSON.parse(server.requests[0].requestBody); + expect(request.imp[0].banner.format[0].w).to.equal(300); + expect(request.imp[0].banner.format[0].h).to.equal(600); + expect(request.imp[0].tagid).to.equal('tagid-1'); + expect(request.imp[0].banner.pos).to.equal(1); + expect(request.imp[0].secure).to.equal(0); + expect(request.site.id).to.equal('89192'); + }); + + it('Should not pass empty or missing optional parameters on requests.', function () { + adapter.callBids(bidderRequest); + server.respond(); + + var request = JSON.parse(server.requests[0].requestBody); + expect(request.imp[1].tagid).to.equal(undefined); + expect(request.imp[2].tagid).to.equal(undefined); + expect(request.imp[1].pos).to.equal(undefined); + }); + + it('Should create the format objects correctly.', function () { + adapter.callBids(bidderRequest); + server.respond(); + + var request = JSON.parse(server.requests[0].requestBody); + expect(request.imp[2].banner.format.length).to.equal(2); + expect(request.imp[2].banner.format[0].w).to.equal(300); + expect(request.imp[2].banner.format[1].w).to.equal(160); + }); + }); }); diff --git a/test/spec/modules/coxBidAdapter_spec.js b/test/spec/modules/coxBidAdapter_spec.js new file mode 100644 index 00000000000..ee1eb991f23 --- /dev/null +++ b/test/spec/modules/coxBidAdapter_spec.js @@ -0,0 +1,120 @@ +import Adapter from 'modules/coxBidAdapter'; +import bidManager from 'src/bidmanager'; +import adLoader from 'src/adloader'; +import {expect} from 'chai'; + +describe('CoxAdapter', () => { + let adapter; + let loadScriptStub; + let addBidResponseSpy; + + let emitScript = (script) => { + let node = document.createElement('script'); + node.type = 'text/javascript'; + node.appendChild(document.createTextNode(script)); + document.getElementsByTagName('head')[0].appendChild(node); + }; + + beforeEach(() => { + adapter = new Adapter(); + addBidResponseSpy = sinon.spy(bidManager, 'addBidResponse'); + }); + + afterEach(() => { + loadScriptStub.restore(); + addBidResponseSpy.restore(); + }); + + describe('response handling', () => { + const normalResponse = 'cdsTag.__callback__({"zones":{"as2000005991707":{"ad" : "

FOO<\/h1>","uid" : "","price" : 1.51,"floor" : 0,}},"tpCookieSync":"

FOOKIE<\/h1>"})'; + const zeroPriceResponse = 'cdsTag.__callback__({"zones":{"as2000005991707":{"ad" : "

DEFAULT FOO<\/h1>","uid" : "","price" : 0,"floor" : 0,}},"tpCookieSync":"

FOOKIE<\/h1>"})'; + const incompleteResponse = 'cdsTag.__callback__({"zones":{},"tpCookieSync":"

FOOKIE<\/h1>"})'; + + const oneBidConfig = { + bidderCode: 'cox', + bids: [{ + bidder: 'cox', + placementCode: 'FOO456789', + sizes: [300, 250], + params: { size: '300x250', id: 2000005991707, siteId: 2000100948180, env: 'PROD' }, + }] + }; + + // ===== 1 + it('should provide a correctly populated Bid given a valid response', () => { + loadScriptStub = sinon.stub(adLoader, 'loadScript', () => { emitScript(normalResponse); }) + + adapter.callBids(oneBidConfig); + + let bid = addBidResponseSpy.args[0][1]; + expect(bid.cpm).to.equal(1.51); + expect(bid.ad).to.be.a('string'); + expect(bid.bidderCode).to.equal('cox'); + }); + + // ===== 2 + it('should provide an empty Bid given a zero-price response', () => { + loadScriptStub = sinon.stub(adLoader, 'loadScript', () => { emitScript(zeroPriceResponse); }) + + adapter.callBids(oneBidConfig); + + let bid = addBidResponseSpy.args[0][1]; + expect(bid.cpm).to.not.be.ok + expect(bid.ad).to.not.be.ok; + }); + + // ===== 3 + it('should provide an empty Bid given an incomplete response', () => { + loadScriptStub = sinon.stub(adLoader, 'loadScript', () => { emitScript(incompleteResponse); }) + + adapter.callBids(oneBidConfig); + + let bid = addBidResponseSpy.args[0][1]; + expect(bid.cpm).to.not.be.ok + expect(bid.ad).to.not.be.ok; + }); + + // ===== 4 + it('should not provide a Bid given no response', () => { + loadScriptStub = sinon.stub(adLoader, 'loadScript', () => { emitScript(''); }); + + adapter.callBids(oneBidConfig); + + expect(addBidResponseSpy.callCount).to.equal(0); + }); + }); + + describe('request generation', () => { + const missingBidsConfig = { + bidderCode: 'cox', + bids: null, + }; + const missingParamsConfig = { + bidderCode: 'cox', + bids: [{ + bidder: 'cox', + placementCode: 'FOO456789', + sizes: [300, 250], + params: null, + }] + }; + + // ===== 5 + it('should not make an ad call given missing bids in config', () => { + loadScriptStub = sinon.stub(adLoader, 'loadScript'); + + adapter.callBids(missingBidsConfig); + + expect(loadScriptStub.callCount).to.equal(0); + }); + + // ===== 6 + it('should not make an ad call given missing params in config', () => { + loadScriptStub = sinon.stub(adLoader, 'loadScript'); + + adapter.callBids(missingParamsConfig); + + expect(loadScriptStub.callCount).to.equal(0); + }); + }); +}); diff --git a/test/spec/adapters/criteo_spec.js b/test/spec/modules/criteoBidAdapter_spec.js similarity index 51% rename from test/spec/adapters/criteo_spec.js rename to test/spec/modules/criteoBidAdapter_spec.js index 5b2159e1594..c686f284134 100644 --- a/test/spec/adapters/criteo_spec.js +++ b/test/spec/modules/criteoBidAdapter_spec.js @@ -1,57 +1,99 @@ -/* jshint -W030 */ - -import Adapter from '../../../src/adapters/criteo'; +import Adapter from '../../../modules/criteoBidAdapter'; import bidManager from '../../../src/bidmanager'; +import {ajax} from '../../../src/ajax' import {expect} from 'chai'; var CONSTANTS = require('../../../src/constants'); -describe('criteo adapter test', () => { +/* ------------ Publishertag stub begin ------------ */ +before(() => { + window.Criteo = { + PubTag: { + DirectBidding: { + DirectBiddingSlot: function DirectBiddingSlot(placementCode, zoneid, nativeCallback, transactionId, sizes) { + return { + impId: placementCode + }; + }, + + DirectBiddingUrlBuilder: function DirectBiddingUrlBuilder(isAudit) { return {} }, + + DirectBiddingEvent: function DirectBiddingEvent(profileId, urlBuilder, slots, success, error, timeout) { + return { + slots: slots, + eval: function () { + var callbacks = { + error: error, + success: success + } + ajax('//bidder.criteo.com/cdb', callbacks) + } + } + } + } + } + }; + + window.criteo_pubtag = window.criteo_pubtag || { + push: function (event) { + event.eval(); + } + } + + window.Criteo.events = window.Criteo.events || []; + window.Criteo.events.push = function (elem) { + if (typeof elem === 'function') { + elem(); + } + }; +}); +/* ------------ Publishertag stub end ------------ */ +describe('criteo adapter test', () => { let adapter; let stubAddBidResponse; let validBid = { - bidderCode: 'criteo', - bids: [ - { - bidder: 'criteo', - placementCode: 'foo', - sizes: [[250, 350]], - params: { - zoneId: 32934, - audit: 'true' - } - } - ] - }; - - let validResponse = {slots: [{impid: "foo", cpm: 1.12, creative: ""}]}; - let invalidResponse = { slots: [{ "impid": "unknownSlot" }] } + bidderCode: 'criteo', + bids: [ + { + bidder: 'criteo', + placementCode: 'foo', + sizes: [[250, 350]], + params: { + zoneId: 32934, + audit: 'true' + } + } + ] + }; + + let validResponse = {slots: [{impid: 'foo', cpm: 1.12, creative: ""}]}; + let invalidResponse = { slots: [{ 'impid': 'unknownSlot' }] } let validMultiBid = { - bidderCode: 'criteo', - bids: [ - { - bidder: 'criteo', - placementCode: 'foo', - sizes: [[250, 350]], - params: { - zoneId: 32934, - audit: 'true' - } - }, - { - bidder: 'criteo', - placementCode: 'bar', - sizes: [[250, 350]], - params: { - zoneId: 32935, - audit: 'true' - } - } - ] - }; + bidderCode: 'criteo', + bids: [ + { + bidder: 'criteo', + placementCode: 'foo', + sizes: [[250, 350]], + params: { + zoneId: 32934, + audit: 'true' + } + }, + { + bidder: 'criteo', + placementCode: 'bar', + sizes: [[250, 350]], + params: { + zoneId: 32935, + audit: 'true' + } + } + ] + }; beforeEach(() => { adapter = new Adapter(); @@ -61,7 +103,7 @@ describe('criteo adapter test', () => { stubAddBidResponse.restore(); }); -describe('adding bids to the manager', () => { + describe('adding bids to the manager', () => { let server; beforeEach(() => { @@ -71,8 +113,8 @@ describe('adding bids to the manager', () => { it('adds bid for valid request', (done) => { stubAddBidResponse = sinon.stub(bidManager, 'addBidResponse', function (adUnitCode, bid) { - expect(bid).to.satisfy(bid => { return bid.getStatusCode() == CONSTANTS.STATUS.GOOD }); - done(); + expect(bid).to.satisfy(bid => { return bid.getStatusCode() == CONSTANTS.STATUS.GOOD }); + done(); }); adapter.callBids(validBid); @@ -81,10 +123,9 @@ describe('adding bids to the manager', () => { it('adds bid for multibid valid request', (done) => { let callCount = 0; stubAddBidResponse = sinon.stub(bidManager, 'addBidResponse', function (adUnitCode, bid) { - callCount++; + callCount++; - if (callCount == 2) - done(); + if (callCount == 2) { done(); } }); adapter.callBids(validMultiBid); @@ -92,8 +133,8 @@ describe('adding bids to the manager', () => { it('adds bidderCode to the response of a valid request', (done) => { stubAddBidResponse = sinon.stub(bidManager, 'addBidResponse', function (adUnitCode, bid) { - expect(bid).to.have.property('bidderCode', 'criteo'); - done(); + expect(bid).to.have.property('bidderCode', 'criteo'); + done(); }); adapter.callBids(validBid); @@ -114,9 +155,9 @@ describe('adding bids to the manager', () => { }); adapter.callBids(validBid); }); -}); + }); -describe('dealing with unexpected situations', () => { + describe('dealing with unexpected situations', () => { let server; beforeEach(() => { @@ -124,33 +165,33 @@ describe('dealing with unexpected situations', () => { }); it('no bid if cdb handler responds with no bid empty string response', (done) => { - server.respondWith(""); + server.respondWith(''); stubAddBidResponse = sinon.stub(bidManager, 'addBidResponse', function (adUnitCode, bid) { - expect(bid).to.satisfy(bid => { return bid.getStatusCode() == CONSTANTS.STATUS.NO_BID }); - done(); + expect(bid).to.satisfy(bid => { return bid.getStatusCode() == CONSTANTS.STATUS.NO_BID }); + done(); }); adapter.callBids(validBid); }); it('no bid if cdb handler responds with no bid empty object response', (done) => { - server.respondWith("{ }"); + server.respondWith('{ }'); stubAddBidResponse = sinon.stub(bidManager, 'addBidResponse', function (adUnitCode, bid) { - expect(bid).to.satisfy(bid => { return bid.getStatusCode() == CONSTANTS.STATUS.NO_BID }); - done(); + expect(bid).to.satisfy(bid => { return bid.getStatusCode() == CONSTANTS.STATUS.NO_BID }); + done(); }); adapter.callBids(validBid); }); it('no bid if cdb handler responds with HTTP error', (done) => { - server.respondWith([500, {}, "Internal Server Error"]); + server.respondWith([500, {}, 'Internal Server Error']); stubAddBidResponse = sinon.stub(bidManager, 'addBidResponse', function (adUnitCode, bid) { - expect(bid).to.satisfy(bid => { return bid.getStatusCode() == CONSTANTS.STATUS.NO_BID }); - done(); + expect(bid).to.satisfy(bid => { return bid.getStatusCode() == CONSTANTS.STATUS.NO_BID }); + done(); }); adapter.callBids(validBid); @@ -160,12 +201,11 @@ describe('dealing with unexpected situations', () => { server.respondWith(JSON.stringify(invalidResponse)); stubAddBidResponse = sinon.stub(bidManager, 'addBidResponse', function (adUnitCode, bid) { - expect(bid).to.satisfy(bid => { return bid.getStatusCode() == CONSTANTS.STATUS.NO_BID }); - done(); + expect(bid).to.satisfy(bid => { return bid.getStatusCode() == CONSTANTS.STATUS.NO_BID }); + done(); }); adapter.callBids(validBid); }); }); - }); diff --git a/test/spec/modules/dfpAdServerVideo_spec.js b/test/spec/modules/dfpAdServerVideo_spec.js new file mode 100644 index 00000000000..81c83baa65c --- /dev/null +++ b/test/spec/modules/dfpAdServerVideo_spec.js @@ -0,0 +1,94 @@ +import { expect } from 'chai'; + +import parse from 'url-parse'; +import buildDfpVideoUrl from 'modules/dfpAdServerVideo'; +import { parseQS } from 'src/url'; +import adUnit from 'test/fixtures/video/adUnit'; + +const bid = { + videoCacheKey: 'abc', + adserverTargeting: { }, +}; + +describe('The DFP video support module', () => { + it('should make a legal request URL when given the required params', () => { + const url = parse(buildDfpVideoUrl({ + adUnit: adUnit, + bid: bid, + params: { + 'iu': 'my/adUnit', + 'description_url': 'someUrl.com', + } + })); + + expect(url.protocol).to.equal('https:'); + expect(url.host).to.equal('pubads.g.doubleclick.net'); + + const queryParams = parseQS(url.query); + expect(queryParams).to.have.property('correlator'); + expect(queryParams).to.have.property('description_url', 'someUrl.com'); + expect(queryParams).to.have.property('env', 'vp'); + expect(queryParams).to.have.property('gdfp_req', '1'); + expect(queryParams).to.have.property('iu', 'my/adUnit'); + expect(queryParams).to.have.property('output', 'xml_vast3'); + expect(queryParams).to.have.property('sz', '640x480'); + expect(queryParams).to.have.property('unviewed_position_start', '1'); + expect(queryParams).to.have.property('url'); + }); + + it('should override param defaults with user-provided ones', () => { + const url = parse(buildDfpVideoUrl({ + adUnit: adUnit, + bid: bid, + params: { + 'iu': 'my/adUnit', + 'output': 'vast', + } + })); + + expect(parseQS(url.query)).to.have.property('output', 'vast'); + }); + + it('should include the cache key and adserver targeting in cust_params', () => { + const bidCopy = Object.assign({ }, bid); + bidCopy.adserverTargeting = { + hb_adid: 'ad_id', + }; + + const url = parse(buildDfpVideoUrl({ + adUnit: adUnit, + bid: bidCopy, + params: { + 'iu': 'my/adUnit' + } + })); + const queryObject = parseQS(url.query); + const customParams = parseQS('?' + decodeURIComponent(queryObject.cust_params)); + + expect(customParams).to.have.property('hb_adid', 'ad_id'); + expect(customParams).to.have.property('hb_uuid', bid.videoCacheKey); + }); + + it('should merge the user-provided cust_params with the default ones', () => { + const bidCopy = Object.assign({ }, bid); + bidCopy.adserverTargeting = { + hb_adid: 'ad_id', + }; + + const url = parse(buildDfpVideoUrl({ + adUnit: adUnit, + bid: bidCopy, + params: { + 'iu': 'my/adUnit', + cust_params: { + 'my_targeting': 'foo', + }, + }, + })); + const queryObject = parseQS(url.query); + const customParams = parseQS('?' + decodeURIComponent(queryObject.cust_params)); + + expect(customParams).to.have.property('hb_adid', 'ad_id'); + expect(customParams).to.have.property('my_targeting', 'foo'); + }); +}); diff --git a/test/spec/modules/districtmDMXBidAdapter_spec.js b/test/spec/modules/districtmDMXBidAdapter_spec.js new file mode 100644 index 00000000000..6fc83d88e6d --- /dev/null +++ b/test/spec/modules/districtmDMXBidAdapter_spec.js @@ -0,0 +1,245 @@ +/** + * Created by stevealliance on 2016-11-15. + */ + +import {expect} from 'chai'; +import {should} from 'chai'; +import Adaptor from '../../../modules/districtmDMXBidAdapter'; + +import adLoader from '../../../src/adloader'; + +var _each = function(obj, fn) { + for (var o in obj) { + fn(o, obj[o]); + } +} + +let districtm; +const PREBID_RESPONSE = function() { + return { + result: { + cpm: '3.45', + callbackId: '1490bd6bdc59ce', + width: 300, + height: 250, + banner: 'html' + }, + callback_uid: '1490bd6bdc59ce' + }; +} +const PREBID_PARAMS = { + bidderCode: 'districtmDMX', + requestId: '5ccedbd5-86c1-436f-8649-964262461eac', + bidderRequestId: '1490bd6bdc59ce', + start: new Date().getTime(), + bids: [{ + bidder: 'districtmDMX', + bidId: '84ab500420319d', + bidderRequestId: '1490bd6bdc59ce', + requestId: '5ccedbd5-86c1-436f-8649-964262461eac', + placementCode: 'golden', + params: { + placement: 109801, + floor: '1.00' + }, + sizes: [[300, 250], [300, 600]] + }] +}; + +function resetDm() { + window.hb_dmx_res = undefined; +} + +function activated() { + window.hb_dmx_res = { + ssp: {}, + bh() { + + }, + auction: { + fixSize(s) { + let size; + if (!Array.isArray(s[0])) { + size = [s[0] + 'x' + s[1]]; + } else { + size = s.map(ss => { + return ss[0] + 'x' + ss[1]; + }) + } + + return size; + }, + + run(a, b, c) { + + } + } + } +} + +function definitions() { + districtm.callBids({ + bidderCode: 'districtmDMX', + bids: [ + { + bidder: 'districtmDMX', + adUnitCode: 'golden', + sizes: [[728, 90]], + params: { + siteId: '101000' + } + }, + { + bidder: 'districtmDMX', + adUnitCode: 'stevealliance', + sizes: [[300, 250]], + params: { + siteId: '101000' + } + } + ] + }); +} +describe('DistrictM adapter test', () => { + describe('File loading', () => { + let districtm; + afterEach(() => { + districtm = new Adaptor(); + adLoader.loadScript(districtm.districtUrl, function() {}); + }) + + it('For loading file ', () => { + expect(!window.hb_dmx_res).to.equal(true); + }) + }) + + describe('check for library do exists', () => { + it('library was not loaded', () => { + expect(!window.hb_dmx_res).to.equal(true); + }) + + it('library is now available', () => { + activated(); + + expect(!!window.hb_dmx_res).to.equal(true); + }) + }) + + describe('Check if size get clean', () => { + beforeEach(() => { + activated(); + }) + it('size clean up using fixe size', () => { + activated(); + + expect(window.hb_dmx_res.auction.fixSize([728, 90])[0]).to.equal(['728x90'][0]); + expect(window.hb_dmx_res.auction.fixSize([[300, 250], [300, 600]]).toString()).to.equal(['300x250', '300x600'].toString()); + }) + }) + + describe('Check call bids return no errors', () => { + let districtm; + beforeEach(() => { + districtm = new Adaptor(); + }); + it('check value push using cal bids', () => { + let obj = districtm.callBids(PREBID_PARAMS); + obj.should.have.property('bidderCode'); + obj.should.have.property('requestId'); + obj.should.have.property('bidderRequestId'); + obj.should.have.property('start'); + obj.should.have.property('bids'); + }) + it('check if value got pass correctly for DM params', () => { + let dm = districtm.callBids(PREBID_PARAMS).bids.map(bid => bid); + dm.forEach(a => { + a.should.have.property('bidder'); + a.should.have.property('requestId'); + a.should.have.property('bidderRequestId'); + a.should.have.property('placementCode'); + a.should.have.property('params'); + a.should.have.property('sizes'); + expect(a.bidder).to.equal('districtmDMX'); + expect(a.placementCode).to.equal('golden'); + expect(a.params.placement).to.equal(109801); + }) + }) + }) + + describe('Run prebid definitions !', () => { + let districtm; + beforeEach(() => { + districtm = new Adaptor(); + }) + + it('Run and return send bids', () => { + let sendBids = districtm.sendBids(PREBID_PARAMS); + sendBids.forEach(sb => { + expect(sb.sizes.toString()).to.equal([[300, 250], [300, 600]].toString()); + }) + }) + }) + + describe('HandlerRes function test', () => { + let districtm; + + beforeEach(() => { + districtm = new Adaptor(); + }) + + it('it\'s now time to play with the response ...', () => { + let result = districtm.handlerRes(PREBID_RESPONSE(), PREBID_PARAMS); + _each(result, function(k, v) { + + }) + + expect(result.cpm).to.equal('3.45'); + expect(result.width).to.equal(300); + expect(result.height).to.equal(250); + expect(result.ad).to.equal('html'); + }) + it('it\'s now time to play with the response failure...', () => { + let result = districtm.handlerRes({result: {cpm: 0}}, PREBID_PARAMS); + + result.should.have.property('bidderCode'); + }) + }) + + describe('look at the adloader', () => { + let districtm; + beforeEach(() => { + districtm = new Adaptor(); + sinon.stub(adLoader, 'loadScript'); + }) + + it('Verify districtm library is downloaded if nessesary', () => { + resetDm(); + districtm.callBids(PREBID_PARAMS); + let libraryLoadCall = adLoader.loadScript.firstCall.args[0]; + let callback = adLoader.loadScript.firstCall.args[1]; + expect(libraryLoadCall).to.equal('http://prebid.districtm.ca/lib.js'); + expect(callback).to.be.a('function'); + }); + + afterEach(() => { + adLoader.loadScript.restore(); + }) + }); + describe('run send bid from within !!!', () => { + beforeEach(() => { + districtm = new Adaptor(); + sinon.stub(districtm, 'sendBids'); + }) + + it('last test on send bids', () => { + resetDm(); + districtm.sendBids(PREBID_PARAMS); + expect(districtm.sendBids.calledOnce).to.be.true; + expect(districtm.sendBids.firstCall.args[0]).to.be.a('object'); + }); + + afterEach(() => { + districtm.sendBids.restore(); + }) + }); +}); diff --git a/test/spec/modules/eplanningBidAdapter_spec.js b/test/spec/modules/eplanningBidAdapter_spec.js new file mode 100644 index 00000000000..ca7c498c610 --- /dev/null +++ b/test/spec/modules/eplanningBidAdapter_spec.js @@ -0,0 +1,112 @@ +describe('eplanning adapter tests', function () { + var urlParse = require('url-parse'); + var querystringify = require('querystringify'); + var adapter = require('modules/eplanningBidAdapter'); + var adLoader = require('src/adloader'); + var expect = require('chai').expect; + var bidmanager = require('src/bidmanager'); + var CONSTANTS = require('src/constants.json'); + + var DEFAULT_PARAMS = { + bidderCode: 'eplanning', + bids: [{ + code: 'div-gpt-ad-1460505748561-0', + sizes: [[300, 250], [300, 200]], + bidder: 'eplanning', + params: { + ci: '18f66' + } + }] + }; + + var PARAMS_SERVER_TEST = { + bidderCode: 'eplanning', + bids: [{ + code: 'div-gpt-ad-1460505748561-0', + sizes: [[300, 250], [300, 600]], + bidder: 'eplanning', + params: { + ci: '18f66', + t: '1' + } + }] + }; + + var RESPONSE_AD = { + bids: [{ + placementCode: 'div-gpt-ad-1460505748561-0', + ad: { + ad: '

test ad

', + cpm: 1, + width: 300, + height: 250 + } + }] + }; + + var RESPONSE_EMPTY = { + bids: [{ + placementCode: 'div-gpt-ad-1460505748561-0' + }] + }; + + var stubAddBidResponse; + + describe('eplanning tests', function() { + beforeEach(function() { + stubAddBidResponse = sinon.stub(bidmanager, 'addBidResponse'); + }); + afterEach(function() { + stubAddBidResponse.restore(); + }); + + it('callback function should exist', function() { + expect(pbjs.processEPlanningResponse).to.exist.and.to.be.a('function'); + }); + + it('creates a bid response if bid exists', function() { + adapter().callBids(DEFAULT_PARAMS); + pbjs.processEPlanningResponse(RESPONSE_AD); + + var bidPlacementCode = stubAddBidResponse.getCall(0).args[0]; + var bidObject = stubAddBidResponse.getCall(0).args[1]; + + expect(bidPlacementCode).to.equal('div-gpt-ad-1460505748561-0'); + expect(bidObject.cpm).to.equal(1); + expect(bidObject.ad).to.equal('

test ad

'); + expect(bidObject.width).to.equal(300); + expect(bidObject.height).to.equal(250); + expect(bidObject.getStatusCode()).to.equal(1); + expect(bidObject.bidderCode).to.equal('eplanning'); + }); + + it('creates an empty bid response if there is no bid', function() { + adapter().callBids(DEFAULT_PARAMS); + pbjs.processEPlanningResponse(RESPONSE_EMPTY); + + var bidPlacementCode = stubAddBidResponse.getCall(0).args[0]; + var bidObject = stubAddBidResponse.getCall(0).args[1]; + + expect(bidPlacementCode).to.equal('div-gpt-ad-1460505748561-0'); + expect(bidObject.getStatusCode()).to.equal(2); + expect(bidObject.bidderCode).to.equal('eplanning'); + }); + + it('creates a bid response and sync users register ad', function() { + adapter().callBids(DEFAULT_PARAMS); + window.hbpb.rH({ + 'sI': { 'k': '18f66' }, + 'sec': { 'k': 'ROS' }, + 'sp': [ { 'k': 'div-gpt-ad-1460505748561-0', 'a': [{ 'w': 300, 'h': 250, 'adm': '

test ad

', 'pr': 1 }] } ], + 'cs': [ + '//test.gif', + { 'j': true, u: '//test.js' }, + { 'ifr': true, u: '//test.html', data: { 'test': 1 } } + ] + }); + var bidPlacementCode = stubAddBidResponse.getCall(0).args[0]; + var bidObject = stubAddBidResponse.getCall(0).args[1]; + expect(bidObject.getStatusCode()).to.equal(2); + }); + }); +}); diff --git a/test/spec/adapters/fidelity_spec.js b/test/spec/modules/fidelityBidAdapter_spec.js similarity index 87% rename from test/spec/adapters/fidelity_spec.js rename to test/spec/modules/fidelityBidAdapter_spec.js index 31ae9378574..5777c6af8cd 100644 --- a/test/spec/adapters/fidelity_spec.js +++ b/test/spec/modules/fidelityBidAdapter_spec.js @@ -1,18 +1,17 @@ describe('fidelity adapter tests', function() { const expect = require('chai').expect; - const adapter = require('src/adapters/fidelity'); - const adLoader = require('src/adloader'); + const adapter = require('modules/fidelityBidAdapter'); + const adLoader = require('src/adloader'); const bidmanager = require('src/bidmanager'); const STATUS = require('src/constants').STATUS; var urlParse = require('url-parse'); var querystringify = require('querystringify'); describe('creation of bid url', function () { - it('should be called', function () { var stubLoadScript; stubLoadScript = sinon.stub(adLoader, 'loadScript'); - + var bidderRequest = { bidderCode: 'fidelity', bids: [ @@ -36,7 +35,7 @@ describe('fidelity adapter tests', function() { it('should populate required parameters', function () { var stubLoadScript; stubLoadScript = sinon.stub(adLoader, 'loadScript'); - + var bidderRequest = { bidderCode: 'fidelity', bids: [ @@ -59,7 +58,7 @@ describe('fidelity adapter tests', function() { it('should populate required and optional parameters', function () { var stubLoadScript; stubLoadScript = sinon.stub(adLoader, 'loadScript'); - + var bidderRequest = { bidderCode: 'fidelity', bids: [ @@ -88,7 +87,7 @@ describe('fidelity adapter tests', function() { expect(parsedBidUrlQueryString).to.have.property('zoneid').and.to.equal('37'); expect(parsedBidUrlQueryString).to.have.property('impid').and.to.equal('bidId-123456-1'); - expect(parsedBidUrlQueryString).to.have.property('callback').and.to.equal('window.$$PREBID_GLOBAL$$.fidelityResponse'); + expect(parsedBidUrlQueryString).to.have.property('callback').and.to.equal('window.$$PREBID_GLOBAL$$.fidelityResponse'); expect(parsedBidUrlQueryString).to.have.property('loc').and.to.equal('http://locurl'); expect(parsedBidUrlQueryString).to.have.property('ct0').and.to.equal('http://clickurl'); expect(parsedBidUrlQueryString).to.have.property('subid').and.to.equal('000'); @@ -96,11 +95,10 @@ describe('fidelity adapter tests', function() { stubLoadScript.restore(); }); }); - - describe('fidelityResponse', function () { + describe('fidelityResponse', function () { it('should exist and be a function', function () { - expect(pbjs.fidelityResponse).to.exist.and.to.be.a('function'); + expect($$PREBID_GLOBAL$$.fidelityResponse).to.exist.and.to.be.a('function'); }); it('should add empty bid response if no bids returned', function () { @@ -122,15 +120,15 @@ describe('fidelity adapter tests', function() { // no bids returned in the response. var response = { - "id": "543210", - "seatbid": [] + 'id': '543210', + 'seatbid': [] }; - pbjs._bidsRequested.push(bidderRequest); + $$PREBID_GLOBAL$$._bidsRequested.push(bidderRequest); // adapter needs to be called, in order for the stub to register. adapter() - pbjs.fidelityResponse(response); + $$PREBID_GLOBAL$$.fidelityResponse(response); var bidPlacementCode1 = stubAddBidResponse.getCall(0).args[0]; var bidObject1 = stubAddBidResponse.getCall(0).args[1]; @@ -161,24 +159,24 @@ describe('fidelity adapter tests', function() { // Returning a single bid in the response. var response = { - "id": "543210", - "seatbid": [ { - "bid" : [ { - "id" : "1111111", - "impid" : "bidId-123456-1", - "price" : 0.09, - "adm" : "<>", - "height" : 90, - "width" : 728 + 'id': '543210', + 'seatbid': [ { + 'bid': [ { + 'id': '1111111', + 'impid': 'bidId-123456-1', + 'price': 0.09, + 'adm': '<>', + 'height': 90, + 'width': 728 } ] } ] }; - pbjs._bidsRequested.push(bidderRequest); + $$PREBID_GLOBAL$$._bidsRequested.push(bidderRequest); // adapter needs to be called, in order for the stub to register. adapter() - pbjs.fidelityResponse(response); + $$PREBID_GLOBAL$$.fidelityResponse(response); var bidPlacementCode1 = stubAddBidResponse.getCall(0).args[0]; var bidObject1 = stubAddBidResponse.getCall(0).args[1]; @@ -194,4 +192,4 @@ describe('fidelity adapter tests', function() { stubAddBidResponse.restore(); }); }); -}); \ No newline at end of file +}); diff --git a/test/spec/adapters/getintent_spec.js b/test/spec/modules/getintentBidAdapter_spec.js similarity index 71% rename from test/spec/adapters/getintent_spec.js rename to test/spec/modules/getintentBidAdapter_spec.js index 64b33ba72ec..e66d2138eaf 100644 --- a/test/spec/adapters/getintent_spec.js +++ b/test/spec/modules/getintentBidAdapter_spec.js @@ -1,11 +1,10 @@ -import Adapter from '../../../src/adapters/getintent'; +import Adapter from '../../../modules/getintentBidAdapter'; import bidManager from '../../../src/bidmanager'; import {expect} from 'chai'; var assert = require('chai').assert; describe('getintent media adapter test', () => { - let adapter; window.gi_hb = { @@ -13,69 +12,69 @@ describe('getintent media adapter test', () => { var pid = bidRequest.pid; var tid = bidRequest.tid; - if (pid == "p1" || pid == "p2") { - callback({ - ad : `Ad Markup ${pid} ${tid}`, - cpm : 2.71, - size : `${bidRequest.size}` - }, bidRequest); - } else if (pid == "p3") { + if (pid == 'p1' || pid == 'p2') { + callback({ + ad: `Ad Markup ${pid} ${tid}`, + cpm: 2.71, + size: `${bidRequest.size}` + }, bidRequest); + } else if (pid == 'p3') { callback({ no_bid: 1 }, bidRequest); - } else if (pid == "p4") { + } else if (pid == 'p4') { callback({ - vast_url : `http://test.com?pid=${pid}&tid=${tid}`, - cpm : 2.88, - size : `${bidRequest.size}` - }, bidRequest); + vast_url: `http://test.com?pid=${pid}&tid=${tid}`, + cpm: 2.88, + size: `${bidRequest.size}` + }, bidRequest); } } }; function callOut() { adapter.callBids({ - bidderCode: "getintent", + bidderCode: 'getintent', bids: [ { - bidder: "getintent", - adUnitCode: "test1", - sizes: [[320,240]], + bidder: 'getintent', + adUnitCode: 'test1', + sizes: [[320, 240]], params: { - pid: "p1", - tid: "t1", - cur: "USD" + pid: 'p1', + tid: 't1', + cur: 'USD' } }, { - bidder: "getintent", - adUnitCode: "test2", - sizes: [[720,90]], + bidder: 'getintent', + adUnitCode: 'test2', + sizes: [[720, 90]], params: { - pid: "p2", - tid: "t1", - cur: "USD" + pid: 'p2', + tid: 't1', + cur: 'USD' } }, { - bidder: "getintent", - adUnitCode: "test3", - sizes: [[400,500]], + bidder: 'getintent', + adUnitCode: 'test3', + sizes: [[400, 500]], params: { - pid: "p3", - tid: "t2", - cur: "USD" + pid: 'p3', + tid: 't2', + cur: 'USD' } }, { - bidder: "getintent", - adUnitCode: "test4", + bidder: 'getintent', + adUnitCode: 'test4', mediaType: 'video', - sizes: [[480,352]], + sizes: [[480, 352]], params: { - pid: "p4", - tid: "t3", - cur: "USD" + pid: 'p4', + tid: 't3', + cur: 'USD' } } ] @@ -90,7 +89,6 @@ describe('getintent media adapter test', () => { }); describe('adding bids to the manager', () => { - let firstBid; let secondBid; let thirdBid; @@ -137,7 +135,7 @@ describe('getintent media adapter test', () => { expect(secondBid).to.have.property('bidderCode', 'getintent'); expect(thirdBid).to.have.property('bidderCode', 'getintent'); }); - + it('will respond to the video bid', () => { expect(videoBid).to.have.property('vastUrl', 'http://test.com?pid=p4&tid=t3'); expect(videoBid).to.have.property('cpm', 2.88); @@ -145,5 +143,4 @@ describe('getintent media adapter test', () => { expect(videoBid).to.have.property('height', '352'); }); }); - }); diff --git a/test/spec/ga_spec.js b/test/spec/modules/googleAnalyticsAdapter_spec.js similarity index 87% rename from test/spec/ga_spec.js rename to test/spec/modules/googleAnalyticsAdapter_spec.js index 65012811f54..4260a831cad 100644 --- a/test/spec/ga_spec.js +++ b/test/spec/modules/googleAnalyticsAdapter_spec.js @@ -1,10 +1,8 @@ var assert = require('assert'); -var ga = require('../../src/adapters/analytics/ga'); +var ga = require('modules/googleAnalyticsAdapter'); describe('Ga', function () { - describe('enableAnalytics', function () { - it('should accept a tracker name option and output prefixed send string', function () { var config = { options: { trackerName: 'foo' } }; ga.enableAnalytics(config); diff --git a/test/spec/adapters/gumgum_spec.js b/test/spec/modules/gumgumBidAdapter_spec.js similarity index 71% rename from test/spec/adapters/gumgum_spec.js rename to test/spec/modules/gumgumBidAdapter_spec.js index 9eb1a36ae08..b90a1a48b15 100644 --- a/test/spec/adapters/gumgum_spec.js +++ b/test/spec/modules/gumgumBidAdapter_spec.js @@ -1,5 +1,5 @@ import {expect} from 'chai'; -import Adapter from '../../../src/adapters/gumgum'; +import Adapter from '../../../modules/gumgumBidAdapter'; import bidManager from '../../../src/bidmanager'; import adLoader from '../../../src/adloader'; import * as utils from '../../../src/utils'; @@ -59,27 +59,27 @@ describe('gumgum adapter', () => { }] }; const pageParams = { - "pvid": "PVID" + 'pvid': 'PVID' }; const bidderResponse = { - "ad": { - "id": 1, - "width": 728, - "height": 90, - "markup": "
some fancy ad
", - "ii": true, - "du": "http://example.com/", - "price": TEST.CPM, - "impurl": "http://example.com/" + 'ad': { + 'id': 1, + 'width': 728, + 'height': 90, + 'markup': '
some fancy ad
', + 'ii': true, + 'du': 'http://example.com/', + 'price': TEST.CPM, + 'impurl': 'http://example.com/' }, - "pag": pageParams + 'pag': pageParams }; function mockBidResponse(response) { sandbox.stub(bidManager, 'addBidResponse'); sandbox.stub(adLoader, 'loadScript'); adapter.callBids(bidderRequest); - pbjs.handleGumGumCB['InScreenBidId'](response); + $$PREBID_GLOBAL$$.handleGumGumCB['InScreenBidId'](response); return bidManager.addBidResponse.firstCall.args[1]; } @@ -92,8 +92,75 @@ describe('gumgum adapter', () => { sandbox.restore(); }); - describe('callBids', () => { + describe('DigiTrust params', () => { + beforeEach(() => { + sandbox.stub(adLoader, 'loadScript'); + }); + + it('should send digiTrust params', () => { + window.DigiTrust = { + getUser: function() {} + }; + sandbox.stub(window.DigiTrust, 'getUser', () => + ({ + success: true, + identity: { + privacy: {optout: false}, + id: 'testId' + } + }) + ); + + adapter.callBids(bidderRequest); + expect(adLoader.loadScript.firstCall.args[0]).to.include('&dt=testId'); + delete window.DigiTrust; + }); + + it('should not send DigiTrust params when DigiTrust is not loaded', () => { + adapter.callBids(bidderRequest); + expect(adLoader.loadScript.firstCall.args[0]).to.not.include('&dt'); + }); + + it('should not send DigiTrust params due to opt out', () => { + window.DigiTrust = { + getUser: function() {} + }; + sandbox.stub(window.DigiTrust, 'getUser', () => + ({ + success: true, + identity: { + privacy: {optout: true}, + id: 'testId' + } + }) + ); + + adapter.callBids(bidderRequest); + expect(adLoader.loadScript.firstCall.args[0]).to.not.include('&dt'); + delete window.DigiTrust; + }); + it('should not send DigiTrust params on failure', () => { + window.DigiTrust = { + getUser: function() {} + }; + sandbox.stub(window.DigiTrust, 'getUser', () => + ({ + success: false, + identity: { + privacy: {optout: false}, + id: 'testId' + } + }) + ); + + adapter.callBids(bidderRequest); + expect(adLoader.loadScript.firstCall.args[0]).to.not.include('&dt'); + delete window.DigiTrust; + }); + }); + + describe('callBids', () => { beforeEach(() => { sandbox.stub(adLoader, 'loadScript'); adapter.callBids(bidderRequest); @@ -136,17 +203,15 @@ describe('gumgum adapter', () => { it('last call should be slot', () => { expect(adLoader.loadScript.lastCall.args[0]).to.include('pi=3'); }); - }); describe('handleGumGumCB[...]', () => { it('exists and is function', () => { - expect(pbjs.handleGumGumCB['InScreenBidId']).to.exist.and.to.be.a('function'); + expect($$PREBID_GLOBAL$$.handleGumGumCB['InScreenBidId']).to.exist.and.to.be.a('function'); }); }); describe('respond with a successful bid', () => { - let successfulBid; beforeEach(() => { @@ -179,11 +244,9 @@ describe('gumgum adapter', () => { expect(successfulBid).to.have.property('width', 728); expect(successfulBid).to.have.property('height', 90); }); - }); describe('respond with an empty bid', () => { - let noBid; beforeEach(() => { @@ -206,11 +269,9 @@ describe('gumgum adapter', () => { it('adds the bidder code to the bid object', () => { expect(noBid).to.have.property('bidderCode', TEST.BIDDER_CODE); }); - }); describe('refresh throttle', () => { - beforeEach(() => { mockBidResponse(bidderResponse); }); @@ -230,7 +291,5 @@ describe('gumgum adapter', () => { warning.to.include(TEST.PLACEMENT); warning.to.include('inScreen'); }); - }); - }); diff --git a/test/spec/adapters/hiromedia_spec.js b/test/spec/modules/hiromediaBidAdapter_spec.js similarity index 67% rename from test/spec/adapters/hiromedia_spec.js rename to test/spec/modules/hiromediaBidAdapter_spec.js index b91bcca38ac..c1ed4ee6e11 100644 --- a/test/spec/adapters/hiromedia_spec.js +++ b/test/spec/modules/hiromediaBidAdapter_spec.js @@ -1,364 +1,331 @@ -/*jslint white: true, es6: true, single: true*/ -/*jshint esversion:6*/ - -import { expect } from 'chai'; -import querystringify from 'querystringify'; -import urlParse from 'url-parse'; - -import adloader from 'src/adloader'; -import Adapter from 'src/adapters/hiromedia'; -import bidmanager from 'src/bidmanager'; -import { STATUS } from 'src/constants'; -import * as utils from 'src/utils'; - -describe('hiromedia adapter', function () { - - const BIDDER_CODE = 'hiromedia'; - const DEFAULT_CALLBACK_NAME = 'hiromedia_callback'; - const DEFAULT_ENDPOINT = 'https://hb-rtb.ktdpublishers.com/bid/get'; - - let adapter; - let sandbox; - let loadScriptStub; - let addBidResponseStub; - let hasValidBidRequestSpy; - let placementId = 0; - - window.$$PREBID_GLOBAL$$ = window.$$PREBID_GLOBAL$$ || {}; - - beforeEach(() => { - - adapter = new Adapter(); - sandbox = sinon.sandbox.create(); - - // Used to spy on bid requests - loadScriptStub = sandbox.stub(adloader, 'loadScript'); - - // Used to spy on bid responses - addBidResponseStub = sandbox.stub(bidmanager, 'addBidResponse'); - - // Used to spy on bid validation - hasValidBidRequestSpy = sandbox.spy(utils, 'hasValidBidRequest'); - - placementId = 0; - - }); - - afterEach(() => { - sandbox.restore(); - }); - - // Helper function that asserts that no bidding activity (requests nor responses) - // was made during a test. - const assertNoBids = () => { - - sinon.assert.notCalled(loadScriptStub); - sinon.assert.notCalled(addBidResponseStub); - - }; - - // Helper function to generate a 'mock' bid object - const makePlacement = (size) => { - - placementId += 1; - - return { - bidder: BIDDER_CODE, - sizes: [size], - params: { - accountId: '1337' - }, - placementCode: 'div-gpt-ad-12345-' + placementId - }; - - }; - - // 300x250 are in the allowed size by default - const tilePlacement = () => makePlacement([300, 250]); - - // anything else should have no bid by default - const leaderPlacement = () => makePlacement([728, 90]); - - describe('callbids', () => { - - it('exists and is a function', () => { - expect(adapter.callBids).to.exist.and.to.be.a('function'); - }); - - it('tolerates empty arguments', () => { - expect(adapter.callBids).to.not.throw(Error); - assertNoBids(); - }); - - it('tolerates empty params', () => { - expect(adapter.callBids.bind(adapter, {})).to.not.throw(Error); - assertNoBids(); - }); - - it('tolerates empty bids', () => { - expect(adapter.callBids.bind(adapter, {bids: []})).to.not.throw(Error); - assertNoBids(); - }); - - it('invokes a bid request per placement', () => { - - const expectedRequests = [{ - batchKey: [DEFAULT_ENDPOINT,'1337','300x250',''].join('-'), - placementCode: 'div-gpt-ad-12345-1', - selectedSize: '300x250' - }, { - batchKey: [DEFAULT_ENDPOINT,'1337','728x90',''].join('-'), - placementCode: 'div-gpt-ad-12345-2', - selectedSize: '728x90' - }]; - - const params = { - bids: [tilePlacement(), leaderPlacement()] - }; - - adapter.callBids(params); - sinon.assert.calledTwice(loadScriptStub); - sinon.assert.notCalled(addBidResponseStub); - sinon.assert.calledTwice(hasValidBidRequestSpy); - - expectedRequests.forEach(function(request, index) { - - expect(hasValidBidRequestSpy.returnValues[index]).to.be.equal(true); - - // validate request - const bidRequest = loadScriptStub.getCall(index).args[0]; - const defaultBidUrl = urlParse(DEFAULT_ENDPOINT); - const bidUrl = urlParse(bidRequest); - const query = querystringify.parse(bidUrl.query); - - expect(bidUrl.hostname).to.equal(defaultBidUrl.hostname); - expect(bidUrl.pathname).to.equal(defaultBidUrl.pathname); - - expect(query).to.have.property('adapterVersion').and.to.equal('3'); - expect(query).to.have.property('callback').and.to.equal('$$PREBID_GLOBAL$$.' + DEFAULT_CALLBACK_NAME); - expect(query).to.have.property('batchKey').and.to.equal(request.batchKey); - expect(query).to.have.property('placementCode').and.to.equal(request.placementCode); - expect(query).to.have.property('accountId').and.to.equal('1337'); - expect(query).to.have.property('selectedSize').and.to.equal(request.selectedSize); - expect(query).to.not.have.property('additionalSizes'); - expect(query).to.have.property('domain').and.to.equal(window.top.location.hostname); - - }); - - }); - - // Test additionalSizes parameter - it('attaches multiple sizes to additionalSizes', () => { - - const placement = tilePlacement(); - - // Append additional - placement.sizes.push([300, 600]); - placement.sizes.push([300, 900]); - - const params = { - bids: [placement] - }; - - adapter.callBids(params); - sinon.assert.calledOnce(loadScriptStub); - - const bidRequest = loadScriptStub.getCall(0).args[0]; - const bidUrl = urlParse(bidRequest); - const query = querystringify.parse(bidUrl.query); - - expect(query).to.have.property('selectedSize').and.to.equal('300x250'); - expect(query).to.have.property('additionalSizes').and.to.equal('300x600,300x900'); - - }); - - // Test `params.accountId` validation - it('invalidates bids with no id', () => { - - const placement = tilePlacement(); - delete placement.params; - - const params = { - bids: [placement] - }; - - adapter.callBids(params); - sinon.assert.notCalled(loadScriptStub); - sinon.assert.calledOnce(hasValidBidRequestSpy); - expect(hasValidBidRequestSpy.returnValues[0]).to.be.equal(false); - - }); - - // Test `params.bidUrl` - it('accepts a custom bid endpoint url', () => { - - const placement = tilePlacement(); - placement.params.bidUrl = DEFAULT_ENDPOINT + '?someparam=value'; - - const params = { - bids: [placement] - }; - - adapter.callBids(params); - sinon.assert.calledOnce(loadScriptStub); - - const bidRequest = loadScriptStub.getCall(0).args[0]; - const defaultBidUrl = urlParse(DEFAULT_ENDPOINT); - const bidUrl = urlParse(bidRequest); - const query = querystringify.parse(bidUrl.query); - - expect(bidUrl.hostname).to.equal(defaultBidUrl.hostname); - expect(bidUrl.pathname).to.equal(defaultBidUrl.pathname); - - expect(query).to.have.property('someparam').and.to.equal('value'); - - }); - - it('batches similar bid requests for similar sized placements', () => { - - const params = { - bids: [tilePlacement(), tilePlacement()] - }; - - adapter.callBids(params); - sinon.assert.calledOnce(loadScriptStub); // and only once! - - }); - - }); - - describe('global response handler', () => { - - const getPbjs = () => window.$$PREBID_GLOBAL$$; - const getResponseHandler = () => window.$$PREBID_GLOBAL$$[DEFAULT_CALLBACK_NAME]; - - it('exists and is a function', () => { - expect(getResponseHandler()).to.exist.and.to.be.a('function'); - }); - - it('tolerates empty arguments', () => { - expect(getResponseHandler()).to.not.throw(Error); - }); - - it('tolerates an empty response', () => { - expect(getResponseHandler().bind(getPbjs(), {})).to.not.throw(Error); - }); - - // This test is coupled with `callBids`, this is done - // to ensure that the response handler is able to - // add bid responses for each placement with the same - // batch key. - // To do this, we have to have the internal state of - // the adapter set up correctly. - it('adds a bid reponse for each pending bid', () => { - - const expectedResponses = [{ - batchKey: [DEFAULT_ENDPOINT,'1337','300x250',''].join('-'), - width: '300', - height: '250', - cpm: 0.4, - ad: '' - }, { - batchKey: [DEFAULT_ENDPOINT,'1337','728x90',''].join('-'), - width: '728', - height: '90', - cpm: 0.4, - ad: '' - }]; - - - // Instead of the dead stub defined in the top scope, we'll use - // one that mocks a response. - loadScriptStub.restore(); - let id = 0; - const activeLoadScriptStub = sandbox.stub(adloader, 'loadScript', (url) => { - const handler = getResponseHandler(); - handler(expectedResponses[id]); - id += 1; - }); - - const params = { - bids: [tilePlacement(), leaderPlacement()] - }; - - adapter.callBids(params); - - sinon.assert.calledTwice(activeLoadScriptStub); - sinon.assert.calledTwice(addBidResponseStub); - - expectedResponses.forEach((expectedResponse, i) => { - - const placementCode = addBidResponseStub.getCall(i).args[0]; - const bidObject = addBidResponseStub.getCall(i).args[1]; - - expect(placementCode).to.be.equal('div-gpt-ad-12345-' + (i + 1)); - - expect(bidObject.getStatusCode()).to.be.equal(STATUS.GOOD); - expect(bidObject).to.have.property('cpm').and.to.equal(expectedResponse.cpm); - expect(bidObject).to.have.property('ad').and.to.equal(expectedResponse.ad); - expect(bidObject).to.have.property('width').and.to.equal(expectedResponse.width); - expect(bidObject).to.have.property('height').and.to.equal(expectedResponse.height); - - }); - - }); - - // We want to check that responses are added according to a sampling value, - // this is possible by stubbing `Math.random`, to ensure the effect is - // limited to the area we check, we create a self destructing stub which - // restores itself once called. - it('adds responses according to the sampling defined in the response', () => { - - const response = { - batchKey: [DEFAULT_ENDPOINT,'1337','300x250',''].join('-'), - cpm: 0.4, - chance: 0.25, - ad: '' - }; - - // List of "random" values. We check that the first two pass and the last - // one is skipped. - const randomValues = [0.2, 0.3]; - let randomIndex = 0; - - loadScriptStub.restore(); - const activeLoadScriptStub = sandbox.stub(adloader, 'loadScript', (url) => { - const handler = getResponseHandler(); - - const mathRandomStub = sandbox.stub(Math, 'random', function () { - - const randomValue = randomValues[randomIndex]; - - randomIndex += 1; - mathRandomStub.restore(); // self destruct on call - - return randomValue; - - }); - - handler(response); - - mathRandomStub.restore(); - - }); - - const params = { - bids: [tilePlacement()] - }; - - adapter.callBids(params); - adapter.callBids(params); - - sinon.assert.calledTwice(addBidResponseStub); - - const firstBidObject = addBidResponseStub.getCall(0).args[1]; - const secondBidObject = addBidResponseStub.getCall(1).args[1]; - - expect(firstBidObject.getStatusCode()).to.be.equal(STATUS.GOOD); - expect(secondBidObject.getStatusCode()).to.be.equal(STATUS.NO_BID); - - }); - - }); - -}); +import { expect } from 'chai'; +import urlParse from 'url-parse'; + +import Adapter from 'modules/hiromediaBidAdapter'; +import bidmanager from 'src/bidmanager'; +import { STATUS } from 'src/constants'; +import * as utils from 'src/utils'; + +describe('hiromedia adapter', function () { + const BIDDER_CODE = 'hiromedia'; + const DEFAULT_ENDPOINT = 'https://hb-rtb.ktdpublishers.com/bid/get'; + + let adapter; + let sandbox; + let xhr; + let addBidResponseStub; + let hasValidBidRequestSpy; + let placementId = 0; + + window.$$PREBID_GLOBAL$$ = window.$$PREBID_GLOBAL$$ || {}; + + beforeEach(() => { + adapter = new Adapter(); + sandbox = sinon.sandbox.create(); + + // Used to spy on bid requests + xhr = sandbox.useFakeXMLHttpRequest(); + + // Used to spy on bid responses + addBidResponseStub = sandbox.stub(bidmanager, 'addBidResponse'); + + // Used to spy on bid validation + hasValidBidRequestSpy = sandbox.spy(utils, 'hasValidBidRequest'); + + placementId = 0; + }); + + afterEach(() => { + sandbox.restore(); + }); + + // Helper function that asserts that no bidding activity (requests nor responses) + // was made during a test. + const assertNoBids = () => { + expect(xhr.requests.length).to.be.equal(0); + sinon.assert.notCalled(addBidResponseStub); + }; + + // Helper function to generate a 'mock' bid object + const makePlacement = (size) => { + placementId += 1; + + return { + bidder: BIDDER_CODE, + sizes: [size], + params: { + accountId: '1337' + }, + placementCode: 'div-gpt-ad-12345-' + placementId + }; + }; + + // 300x250 are in the allowed size by default + const tilePlacement = () => makePlacement([300, 250]); + + // anything else should have no bid by default + const leaderPlacement = () => makePlacement([728, 90]); + + describe('callbids', () => { + it('exists and is a function', () => { + expect(adapter.callBids).to.exist.and.to.be.a('function'); + }); + + it('tolerates empty arguments', () => { + expect(adapter.callBids).to.not.throw(Error); + assertNoBids(); + }); + + it('tolerates empty params', () => { + expect(adapter.callBids.bind(adapter, {})).to.not.throw(Error); + assertNoBids(); + }); + + it('tolerates empty bids', () => { + expect(adapter.callBids.bind(adapter, {bids: []})).to.not.throw(Error); + assertNoBids(); + }); + + it('invokes a bid request per placement', () => { + const expectedRequests = [{ + placementCode: 'div-gpt-ad-12345-1', + selectedSize: '300x250' + }, { + placementCode: 'div-gpt-ad-12345-2', + selectedSize: '728x90' + }, { + placementCode: 'div-gpt-ad-12345-3', + selectedSize: '300x250' + }]; + + const params = { + bids: [tilePlacement(), leaderPlacement(), tilePlacement()] + }; + + adapter.callBids(params); + expect(xhr.requests.length).to.equal(3); + sinon.assert.notCalled(addBidResponseStub); + sinon.assert.calledThrice(hasValidBidRequestSpy); + + expectedRequests.forEach(function(request, index) { + expect(hasValidBidRequestSpy.returnValues[index]).to.be.equal(true); + + // validate request + const bidRequest = xhr.requests[index].url; + const defaultBidUrl = urlParse(DEFAULT_ENDPOINT); + const bidUrl = urlParse(bidRequest, true); + const query = bidUrl.query; + + expect(bidUrl.hostname).to.equal(defaultBidUrl.hostname); + expect(bidUrl.pathname).to.equal(defaultBidUrl.pathname); + + expect(query).to.have.property('adapterVersion').and.to.equal('3'); + expect(query).to.have.property('placementCode').and.to.equal(request.placementCode); + expect(query).to.have.property('accountId').and.to.equal('1337'); + expect(query).to.have.property('selectedSize').and.to.equal(request.selectedSize); + expect(query).to.not.have.property('additionalSizes'); + expect(query).to.have.property('domain').and.to.equal(window.top.location.hostname); + }); + }); + + // Test additionalSizes parameter + it('attaches multiple sizes to additionalSizes', () => { + const placement = tilePlacement(); + + // Append additional + placement.sizes.push([300, 600]); + placement.sizes.push([300, 900]); + + const params = { + bids: [placement] + }; + + adapter.callBids(params); + expect(xhr.requests.length).to.be.equal(1); + + const bidRequest = xhr.requests[0].url; + const bidUrl = urlParse(bidRequest, true); + const query = bidUrl.query; + + expect(query).to.have.property('selectedSize').and.to.equal('300x250'); + expect(query).to.have.property('additionalSizes').and.to.equal('300x600,300x900'); + }); + + // Test `params.accountId` validation + it('invalidates bids with no id', () => { + const placement = tilePlacement(); + delete placement.params; + + const params = { + bids: [placement] + }; + + adapter.callBids(params); + expect(xhr.requests.length).to.be.equal(0); + sinon.assert.calledOnce(hasValidBidRequestSpy); + sinon.assert.calledOnce(addBidResponseStub); + + expect(hasValidBidRequestSpy.returnValues[0]).to.be.equal(false); + const placementCode = addBidResponseStub.getCall(0).args[0]; + const bidObject = addBidResponseStub.getCall(0).args[1]; + + expect(placementCode).to.be.equal('div-gpt-ad-12345-1'); + expect(bidObject.getStatusCode()).to.be.equal(STATUS.NO_BID); + }); + + // Test `params.bidUrl` + it('accepts a custom bid endpoint url', () => { + const placement = tilePlacement(); + placement.params.bidUrl = DEFAULT_ENDPOINT + '?someparam=value'; + + const params = { + bids: [placement] + }; + + adapter.callBids(params); + expect(xhr.requests.length).to.be.equal(1); + + const bidRequest = xhr.requests[0].url; + const defaultBidUrl = urlParse(DEFAULT_ENDPOINT); + const bidUrl = urlParse(bidRequest, true); + const query = bidUrl.query; + + expect(bidUrl.hostname).to.equal(defaultBidUrl.hostname); + expect(bidUrl.pathname).to.equal(defaultBidUrl.pathname); + + expect(query).to.have.property('someparam').and.to.equal('value'); + }); + }); + + describe('response handler', () => { + let server; + + beforeEach(() => { + server = sandbox.useFakeServer(); + }); + + const assertSingleFailedBidResponse = () => { + sinon.assert.calledOnce(addBidResponseStub); + const placementCode = addBidResponseStub.getCall(0).args[0]; + const bidObject = addBidResponseStub.getCall(0).args[1]; + + expect(placementCode).to.be.equal('div-gpt-ad-12345-1'); + expect(bidObject.getStatusCode()).to.be.equal(STATUS.NO_BID); + }; + + it('tolerates an empty response', () => { + server.respondWith(''); + adapter.callBids({bids: [tilePlacement()]}); + server.respond(); + + assertSingleFailedBidResponse(); + }); + + it('tolerates a response error', () => { + server.respondWith([500, {}, '']); + adapter.callBids({bids: [tilePlacement()]}); + server.respond(); + + assertSingleFailedBidResponse(); + }); + + it('tolerates an invalid response', () => { + server.respondWith('not json'); + adapter.callBids({bids: [tilePlacement()]}); + server.respond(); + + assertSingleFailedBidResponse(); + }); + + it('adds a bid reponse for each pending bid', () => { + const responses = [{ + width: '300', + height: '250', + cpm: 0.4, + ad: '' + }, { + width: '728', + height: '90', + cpm: 0.4, + ad: '' + }]; + + let id = 0; + server.respondWith((request) => { + request.respond(200, {}, JSON.stringify(responses[id])); + id += 1; + }); + + const params = { + bids: [tilePlacement(), leaderPlacement()] + }; + + adapter.callBids(params); + server.respond(); + + expect(server.requests.length).to.be.equal(2); + sinon.assert.calledTwice(addBidResponseStub); + + responses.forEach((expectedResponse, i) => { + const placementCode = addBidResponseStub.getCall(i).args[0]; + const bidObject = addBidResponseStub.getCall(i).args[1]; + + expect(placementCode).to.be.equal('div-gpt-ad-12345-' + (i + 1)); + + expect(bidObject.getStatusCode()).to.be.equal(STATUS.GOOD); + expect(bidObject).to.have.property('cpm').and.to.equal(expectedResponse.cpm); + expect(bidObject).to.have.property('ad').and.to.equal(expectedResponse.ad); + expect(bidObject).to.have.property('width').and.to.equal(expectedResponse.width); + expect(bidObject).to.have.property('height').and.to.equal(expectedResponse.height); + }); + }); + + // We want to check that responses are added according to a sampling value, + // this is possible by stubbing `Math.random`, to ensure the effect is + // limited to the area we check, we create a self destructing stub which + // restores itself once called. + it('adds responses according to the sampling defined in the response', () => { + const response = { + cpm: 0.4, + chance: 0.25, + ad: '' + }; + + // List of "random" values. We check that the first two pass and the last + // one is skipped. + const randomValues = [0.2, 0.3]; + let randomIndex = 0; + + server.respondWith((request) => { + const mathRandomStub = sandbox.stub(Math, 'random', function () { + const randomValue = randomValues[randomIndex]; + + randomIndex += 1; + mathRandomStub.restore(); // self destruct on call + + return randomValue; + }); + + request.respond(200, {}, JSON.stringify(response)); + + mathRandomStub.restore(); + }); + + const params = { + bids: [tilePlacement()] + }; + + adapter.callBids(params); + adapter.callBids(params); + server.respond(); + + sinon.assert.calledTwice(addBidResponseStub); + + const firstBidObject = addBidResponseStub.getCall(0).args[1]; + const secondBidObject = addBidResponseStub.getCall(1).args[1]; + + expect(firstBidObject.getStatusCode()).to.be.equal(STATUS.GOOD); + expect(secondBidObject.getStatusCode()).to.be.equal(STATUS.NO_BID); + }); + }); +}); diff --git a/test/spec/modules/huddledmassesBidAdapter_spec.js b/test/spec/modules/huddledmassesBidAdapter_spec.js new file mode 100644 index 00000000000..f4cc12dde1b --- /dev/null +++ b/test/spec/modules/huddledmassesBidAdapter_spec.js @@ -0,0 +1,127 @@ +import { expect } from 'chai'; +import Adapter from '../../../modules/huddledmassesBidAdapter'; +import adapterManager from 'src/adaptermanager'; +import bidManager from 'src/bidmanager'; +import CONSTANTS from 'src/constants.json'; + +describe('HuddledMasses adapter tests', function () { + let sandbox; + const adUnit = { + code: 'huddledmasses', + sizes: [[300, 250], [300, 600]], + bids: [{ + bidder: 'huddledmasses', + params: { + placement_id: 0 + } + }] + }; + + const response = { + ad_id: 15, + adm: '
Bid Response
', + cpm: 0.712, + deal: '5e1f0a8f2aa1', + width: 300, + height: 250 + }; + + beforeEach(() => { + sandbox = sinon.sandbox.create(); + }); + + afterEach(() => { + sandbox.restore(); + }); + + describe('HuddledMasses callBids validation', () => { + let bids, + server; + + beforeEach(() => { + bids = []; + server = sinon.fakeServer.create(); + sandbox.stub(bidManager, 'addBidResponse', (elemId, bid) => { + bids.push(bid); + }); + }); + + afterEach(() => { + server.restore(); + }); + + let adapter = adapterManager.bidderRegistry['huddledmasses']; + + it('Valid bid-request', () => { + sandbox.stub(adapter, 'callBids'); + adapterManager.callBids({ + adUnits: [clone(adUnit)] + }); + + let bidderRequest = adapter.callBids.getCall(0).args[0]; + + expect(bidderRequest).to.have.property('bids') + .that.is.an('array') + .with.lengthOf(1); + + expect(bidderRequest).to.have.deep.property('bids[0]') + .to.have.property('bidder', 'huddledmasses'); + + expect(bidderRequest).to.have.deep.property('bids[0]') + .with.property('sizes') + .that.is.an('array') + .with.lengthOf(2) + .that.deep.equals(adUnit.sizes); + expect(bidderRequest).to.have.deep.property('bids[0]') + .with.property('params') + .to.have.property('placement_id', 0); + }); + + it('Valid bid-response', () => { + server.respondWith(JSON.stringify( + response + )); + adapterManager.callBids({ + adUnits: [clone(adUnit)] + }); + server.respond(); + + expect(bids).to.be.lengthOf(1); + expect(bids[0].getStatusCode()).to.equal(CONSTANTS.STATUS.GOOD); + expect(bids[0].bidderCode).to.equal('huddledmasses'); + expect(bids[0].width).to.equal(300); + expect(bids[0].height).to.equal(250); + expect(bids[0].cpm).to.equal(0.712); + expect(bids[0].dealId).to.equal('5e1f0a8f2aa1'); + }); + }); + + describe('MAS mapping / ordering', () => { + let masSizeOrdering = Adapter.masSizeOrdering; + + it('should not include values without a proper mapping', () => { + let ordering = masSizeOrdering([[320, 50], [42, 42], [300, 250], [640, 480], [0, 0]]); + expect(ordering).to.deep.equal([15, 43, 65]); + }); + + it('should sort values without any MAS priority sizes in regular ascending order', () => { + let ordering = masSizeOrdering([[320, 50], [640, 480], [200, 600]]); + expect(ordering).to.deep.equal([43, 65, 119]); + }); + + it('should sort MAS priority sizes in the proper order w/ rest ascending', () => { + let ordering = masSizeOrdering([[320, 50], [640, 480], [300, 250], [200, 600]]); + expect(ordering).to.deep.equal([15, 43, 65, 119]); + + ordering = masSizeOrdering([[320, 50], [300, 250], [640, 480], [200, 600], [728, 90]]); + expect(ordering).to.deep.equal([15, 2, 43, 65, 119]); + + ordering = masSizeOrdering([ [320, 50], [640, 480], [200, 600], [728, 90]]); + expect(ordering).to.deep.equal([2, 43, 65, 119]); + }) + }); +}); + +function clone(obj) { + return JSON.parse(JSON.stringify(obj)); +} diff --git a/test/spec/modules/indexExchangeBidAdapter_request_spec.js b/test/spec/modules/indexExchangeBidAdapter_request_spec.js new file mode 100644 index 00000000000..ef01e053a5c --- /dev/null +++ b/test/spec/modules/indexExchangeBidAdapter_request_spec.js @@ -0,0 +1,457 @@ +import Adapter from '../../../modules/indexExchangeBidAdapter'; +import adLoader from '../../../src/adloader'; + +var assert = require('chai').assert; +var IndexUtils = require('../../helpers/index_adapter_utils.js'); +var HeaderTagRequest = '/cygnus'; +var SlotThreshold = 20; +var ADAPTER_CODE = 'indexExchange'; + +describe('indexExchange adapter - Request', function () { + let adapter; + let sandbox; + + beforeEach(function() { + window._IndexRequestData = {}; + _IndexRequestData.impIDToSlotID = {}; + _IndexRequestData.reqOptions = {}; + _IndexRequestData.targetIDToResp = {}; + window.cygnus_index_args = {}; + + adapter = new Adapter(); + sandbox = sinon.sandbox.create(); + sandbox.stub(adLoader, 'loadScript'); + }); + + afterEach(function() { + sandbox.restore(); + }); + + it('test_prebid_indexAdapter_parameter_x3: prebid sends AS request -> x3 parameter does not exist in the request', function () { + var configuredBids = IndexUtils.createBidSlots(); + adapter.callBids({ bids: configuredBids }); + + assert.notInclude(adLoader.loadScript.firstCall.args[0], 'x3=', 'x3 parameter is not in AS request'); + }); + + it('test_prebid_indexAdapter_request_1_1: single slot with single size -> single request object for the slot', function () { + var configuredBids = IndexUtils.createBidSlots(); + adapter.callBids({ bids: configuredBids }); + + assert.isTrue(adLoader.loadScript.called, 'loadScript get request'); + + assert.include(adLoader.loadScript.firstCall.args[0], HeaderTagRequest, 'request is headertag request'); + + var requestJSON = IndexUtils.parseIndexRequest(adLoader.loadScript.firstCall.args[0]); + assert.isNotNull(requestJSON.r.imp, 'headertag request include impression object'); + + var impressionObj = requestJSON.r.imp; + + var expandedBids = configuredBids.map(bid => IndexUtils.expandSizes(bid)) + var sidMatched = IndexUtils.matchBidsOnSID(expandedBids, impressionObj); + for (var i = 0; i < sidMatched.matched.length; i++) { + var pair = sidMatched.matched[i]; + + assert.equal(pair.sent.banner.w, pair.configured.size[0], 'request ' + pair.name + ' width is set to ' + pair.configured.size[0]); + assert.equal(pair.sent.banner.h, pair.configured.size[1], 'request ' + pair.name + ' width is set to ' + pair.configured.size[1]); + assert.equal(pair.sent.ext.siteID, pair.configured.params.siteID, 'request ' + pair.name + ' siteID is set to ' + pair.configured.params.siteID); + } + + assert.equal(sidMatched.unmatched.configured.length, 0, 'All configured bids are in impression Obj'); + assert.equal(sidMatched.unmatched.sent.length, 0, 'All bids in impression object are from configured bids'); + assert.isString(requestJSON.r.id, 'ID is string'); + }); + + it('test_prebid_indexAdapter_request_1_1: single slot with single size -> single request object for the slot', function () { + var configuredBids = IndexUtils.createBidSlots(); + adapter.callBids({ bids: configuredBids }); + + assert.isTrue(adLoader.loadScript.called, 'loadScript get request'); + + assert.include(adLoader.loadScript.firstCall.args[0], HeaderTagRequest, 'request is headertag request'); + + var requestJSON = IndexUtils.parseIndexRequest(adLoader.loadScript.firstCall.args[0]); + assert.isNotNull(requestJSON.r.imp, 'headertag request include impression object'); + + var impressionObj = requestJSON.r.imp; + + var expandedBids = configuredBids.map(bid => IndexUtils.expandSizes(bid)) + var sidMatched = IndexUtils.matchBidsOnSID(expandedBids, impressionObj); + for (var i = 0; i < sidMatched.matched.length; i++) { + var pair = sidMatched.matched[i]; + + assert.equal(pair.sent.banner.w, pair.configured.size[0], 'request ' + pair.name + ' width is set to ' + pair.configured.size[0]); + assert.equal(pair.sent.banner.h, pair.configured.size[1], 'request ' + pair.name + ' width is set to ' + pair.configured.size[1]); + assert.equal(pair.sent.ext.siteID, pair.configured.params.siteID, 'request ' + pair.name + ' siteID is set to ' + pair.configured.params.siteID); + } + + assert.equal(sidMatched.unmatched.configured.length, 0, 'All configured bids are in impression Obj'); + assert.equal(sidMatched.unmatched.sent.length, 0, 'All bids in impression object are from configured bids'); + }); + + it('test_prebid_indexAdapter_request_1_2: single slot with unsupported single size -> indexExchange does not participate in auction', function () { + var configuredBids = [ + IndexUtils.createBidSlot(IndexUtils.DefaultPlacementCodePrefix, 'slot_1', [ IndexUtils.unsupportedSizes[0] ]) + ]; + adapter.callBids({ bids: configuredBids }); + + assert.isUndefined(adLoader.loadScript.firstCall.args[0], 'no request made to AS'); + }); + + it('test_prebid_indexAdapter_request_2_1: single slot with all supported multiple sizes -> multiple request objects for the slot', function () { + var configuredBids = IndexUtils.createBidSlots(1, 5); + adapter.callBids({ bids: configuredBids }); + + assert.isTrue(adLoader.loadScript.called, 'loadScript get request'); + assert.include(adLoader.loadScript.firstCall.args[0], HeaderTagRequest, 'request is headertag request'); + + var requestJSON = IndexUtils.parseIndexRequest(adLoader.loadScript.firstCall.args[0]); + assert.isNotNull(requestJSON.r.imp, 'headertag request include impression object'); + + var impressionObj = requestJSON.r.imp; + + var expandedBids = configuredBids.map(bid => IndexUtils.expandSizes(bid)) + var sidMatched = IndexUtils.matchBidsOnSID(expandedBids, impressionObj); + for (var i = 0; i < sidMatched.matched.length; i++) { + var pair = sidMatched.matched[i]; + + assert.equal(pair.sent.banner.w, pair.configured.size[0], 'request ' + pair.name + ' width is set to ' + pair.configured.size[0]); + assert.equal(pair.sent.banner.h, pair.configured.size[1], 'request ' + pair.name + ' width is set to ' + pair.configured.size[1]); + assert.equal(pair.sent.ext.siteID, pair.configured.params.siteID, 'request ' + pair.name + ' siteID is set to ' + pair.configured.params.siteID); + } + + assert.equal(sidMatched.unmatched.configured.length, 0, 'All configured bids are in impression Obj'); + assert.equal(sidMatched.unmatched.sent.length, 0, 'All bids in impression object are from configured bids'); + }); + + it('test_prebid_indexAdapter_request_2_2: single slot with all unsupported multiple sizes -> no request objects for the slot', function () { + var isSetExpectedBidsCountCalled = false; + + var configuredBids = [ + IndexUtils.createBidSlot(IndexUtils.DefaultPlacementCodePrefix, 'slot_1', [ IndexUtils.unsupportedSizes[0], IndexUtils.unsupportedSizes[1], IndexUtils.unsupportedSizes[2] ]) + ]; + adapter.callBids({ bids: configuredBids }); + + assert.isUndefined(adLoader.loadScript.firstCall.args[0], 'no request made to AS'); + }); + + it('test_prebid_indexAdapter_request_2_3: single slot with supported, unsupportrd, supported sizes -> only the supported size request objects for the slot', function () { + var unsupportedSize = IndexUtils.unsupportedSizes[0]; + var configuredBids = [ + IndexUtils.createBidSlot(IndexUtils.DefaultPlacementCodePrefix, 'slot_1', [ IndexUtils.supportedSizes[0], unsupportedSize, IndexUtils.supportedSizes[1] ]) + ]; + adapter.callBids({ bids: configuredBids }); + + assert.isTrue(adLoader.loadScript.called, 'loadScript get request'); + assert.include(adLoader.loadScript.firstCall.args[0], HeaderTagRequest, 'request is headertag request'); + + var requestJSON = IndexUtils.parseIndexRequest(adLoader.loadScript.firstCall.args[0]); + assert.isNotNull(requestJSON.r.imp, 'headertag request include impression object'); + + var impressionObj = requestJSON.r.imp; + var expandedBids = configuredBids.map(bid => IndexUtils.expandSizes(bid)) + + var sidMatched = IndexUtils.matchBidsOnSize(expandedBids, impressionObj); + for (var i = 0; i < sidMatched.matched.length; i++) { + var pair = sidMatched.matched[i]; + assert.equal(pair.sent.banner.w, pair.configured.size[0], 'request ' + pair.name + ' width is set to ' + pair.configured.size[0]); + assert.equal(pair.sent.banner.h, pair.configured.size[1], 'request ' + pair.name + ' width is set to ' + pair.configured.size[1]); + assert.equal(pair.sent.ext.siteID, pair.configured.params.siteID, 'request ' + pair.name + ' siteID is set to ' + pair.configured.params.siteID); + } + + assert.equal(sidMatched.unmatched.sent.length, 0, 'All bids in impression object are from configured bids'); + + assert.equal(sidMatched.unmatched.configured.length, 1, '1 configured bid is not in impression Obj'); + assert.equal(sidMatched.unmatched.configured[0].size, unsupportedSize, 'configured bid not in impression obj size width is' + JSON.stringify(unsupportedSize)); + }); + + it('test_prebid_indexAdapter_request_2_4: single slot with unsupported, supportrd, unsupported sizes -> only the supported size request objects for the slot', function () { + var unsupportedSize1 = IndexUtils.unsupportedSizes[0]; + var unsupportedSize2 = IndexUtils.unsupportedSizes[1]; + var configuredBids = [ + IndexUtils.createBidSlot(IndexUtils.DefaultPlacementCodePrefix, 'slot_1', [ unsupportedSize1, IndexUtils.supportedSizes[1], unsupportedSize2 ]) + ]; + adapter.callBids({ bids: configuredBids }); + + assert.isTrue(adLoader.loadScript.called, 'loadScript get request'); + assert.include(adLoader.loadScript.firstCall.args[0], HeaderTagRequest, 'request is headertag request'); + + var requestJSON = IndexUtils.parseIndexRequest(adLoader.loadScript.firstCall.args[0]); + assert.isNotNull(requestJSON.r.imp, 'headertag request include impression object'); + + var impressionObj = requestJSON.r.imp; + var expandedBids = configuredBids.map(bid => IndexUtils.expandSizes(bid)) + + var sidMatched = IndexUtils.matchBidsOnSize(expandedBids, impressionObj); + for (var i = 0; i < sidMatched.matched.length; i++) { + var pair = sidMatched.matched[i]; + + assert.equal(pair.sent.banner.w, pair.configured.size[0], 'request ' + pair.name + ' width is set to ' + pair.configured.size[0]); + assert.equal(pair.sent.banner.h, pair.configured.size[1], 'request ' + pair.name + ' width is set to ' + pair.configured.size[1]); + assert.equal(pair.sent.ext.siteID, pair.configured.params.siteID, 'request ' + pair.name + ' siteID is set to ' + pair.configured.params.siteID); + } + + assert.equal(sidMatched.unmatched.sent.length, 0, 'All bids in impression object are from configured bids'); + + assert.equal(sidMatched.unmatched.configured.length, 2, '2 configured bid is not in impression Obj'); + assert.equal(sidMatched.unmatched.configured[0].size, unsupportedSize1, 'configured bid not in impression obj size width is' + JSON.stringify(unsupportedSize1)); + assert.equal(sidMatched.unmatched.configured[1].size, unsupportedSize2, 'configured bid not in impression obj size width is' + JSON.stringify(unsupportedSize2)); + }); + + it('test_prebid_indexAdapter_request_3: multiple slots with single size below allowed slot threshold -> request for all the slots', function () { + var configuredBids = IndexUtils.createBidSlots(10); + adapter.callBids({ bids: configuredBids }); + + assert.isTrue(adLoader.loadScript.called, 'loadScript get request'); + assert.include(adLoader.loadScript.firstCall.args[0], HeaderTagRequest, 'request is headertag request'); + + var requestJSON = IndexUtils.parseIndexRequest(adLoader.loadScript.firstCall.args[0]); + assert.isNotNull(requestJSON.r.imp, 'headertag request include impression object'); + + var impressionObj = requestJSON.r.imp; + + var expandedBids = configuredBids.map(bid => IndexUtils.expandSizes(bid)) + var sidMatched = IndexUtils.matchBidsOnSID(expandedBids, impressionObj); + for (var i = 0; i < sidMatched.matched.length; i++) { + var pair = sidMatched.matched[i]; + + assert.equal(pair.sent.banner.w, pair.configured.size[0], 'request ' + pair.name + ' width is set to ' + pair.configured.size[0]); + assert.equal(pair.sent.banner.h, pair.configured.size[1], 'request ' + pair.name + ' width is set to ' + pair.configured.size[1]); + assert.equal(pair.sent.ext.siteID, pair.configured.params.siteID, 'request ' + pair.name + ' siteID is set to ' + pair.configured.params.siteID); + } + + assert.equal(sidMatched.unmatched.configured.length, 0, 'All configured bids are in impression Obj'); + assert.equal(sidMatched.unmatched.sent.length, 0, 'All bids in impression object are from configured bids'); + }); + + it('test_prebid_indexAdapter_request_4: multiple slots with single size at exact allowed slot threshold -> request for all the slots', function () { + var configuredBids = IndexUtils.createBidSlots(SlotThreshold); + adapter.callBids({ bids: configuredBids }); + + assert.isTrue(adLoader.loadScript.called, 'loadScript get request'); + assert.include(adLoader.loadScript.firstCall.args[0], HeaderTagRequest, 'request is headertag request'); + + var requestJSON = IndexUtils.parseIndexRequest(adLoader.loadScript.firstCall.args[0]); + assert.isNotNull(requestJSON.r.imp, 'headertag request include impression object'); + + var impressionObj = requestJSON.r.imp; + + var expandedBids = configuredBids.map(bid => IndexUtils.expandSizes(bid)) + var sidMatched = IndexUtils.matchBidsOnSID(expandedBids, impressionObj); + for (var i = 0; i < sidMatched.matched.length; i++) { + var pair = sidMatched.matched[i]; + + assert.equal(pair.sent.banner.w, pair.configured.size[0], 'request ' + pair.name + ' width is set to ' + pair.configured.size[0]); + assert.equal(pair.sent.banner.h, pair.configured.size[1], 'request ' + pair.name + ' width is set to ' + pair.configured.size[1]); + assert.equal(pair.sent.ext.siteID, pair.configured.params.siteID, 'request ' + pair.name + ' siteID is set to ' + pair.configured.params.siteID); + } + + assert.equal(sidMatched.unmatched.configured.length, 0, 'All configured bids are in impression Obj'); + assert.equal(sidMatched.unmatched.sent.length, 0, 'All bids in impression object are from configured bids'); + }); + + it('test_prebid_indexAdapter_request_5: multiple slots with single size exceed allowed slot threshold -> request for all the slots', function () { + var requestSlotNumber = SlotThreshold + 1; + var configuredBids = IndexUtils.createBidSlots(requestSlotNumber); + adapter.callBids({ bids: configuredBids }); + + assert.isTrue(adLoader.loadScript.called, 'loadScript get request'); + assert.include(adLoader.loadScript.firstCall.args[0], HeaderTagRequest, 'request is headertag request'); + + var requestJSON = IndexUtils.parseIndexRequest(adLoader.loadScript.firstCall.args[0]); + assert.isNotNull(requestJSON.r.imp, 'headertag request include impression object'); + + var impressionObj = requestJSON.r.imp; + + var expandedBids = configuredBids.map(bid => IndexUtils.expandSizes(bid)) + var sidMatched = IndexUtils.matchBidsOnSID(expandedBids, impressionObj); + + for (var i = 0; i < sidMatched.matched.length; i++) { + var pair = sidMatched.matched[i]; + + assert.equal(pair.sent.banner.w, pair.configured.size[0], 'request ' + pair.name + ' width is set to ' + pair.configured.size[0]); + assert.equal(pair.sent.banner.h, pair.configured.size[1], 'request ' + pair.name + ' width is set to ' + pair.configured.size[1]); + assert.equal(pair.sent.ext.siteID, pair.configured.params.siteID, 'request ' + pair.name + ' siteID is set to ' + pair.configured.params.siteID); + } + + assert.equal(sidMatched.unmatched.configured.length, 0, 'All configured bids are in impression Obj'); + assert.equal(sidMatched.unmatched.sent.length, 0, 'All bids in impression object are from configured bids'); + }); + + it('test_prebid_indexAdapter_request_6: threshold valid + non valid which exceeds threshold -> 1 Ad Server request with supported sizes only', function () { + var unsupportedSizeCount = 1; + var requestSlotNumber = SlotThreshold; + var configuredBids = IndexUtils.createBidSlots(requestSlotNumber); + // add additional unsupported sized slot + var invalidSlotPlacement = IndexUtils.DefaultPlacementCodePrefix + 'invalid'; + var invalidSlotID = 'slot-invalid'; + configuredBids.push(IndexUtils.createBidSlot(invalidSlotPlacement, invalidSlotID, [ IndexUtils.unsupportedSizes[0] ])); + + adapter.callBids({ bids: configuredBids }); + + assert.isTrue(adLoader.loadScript.called, 'loadScript get request'); + assert.include(adLoader.loadScript.firstCall.args[0], HeaderTagRequest, 'request is headertag request'); + + var requestJSON = IndexUtils.parseIndexRequest(adLoader.loadScript.firstCall.args[0]); + assert.isNotNull(requestJSON.r.imp, 'headertag request include impression object'); + + var impressionObj = requestJSON.r.imp; + + var expandedBids = configuredBids.map(bid => IndexUtils.expandSizes(bid)) + var sidMatched = IndexUtils.matchBidsOnSID(expandedBids, impressionObj); + + for (var i = 0; i < sidMatched.matched.length; i++) { + var pair = sidMatched.matched[i]; + + assert.equal(pair.sent.banner.w, pair.configured.size[0], 'request ' + pair.name + ' width is set to ' + pair.configured.size[0]); + assert.equal(pair.sent.banner.h, pair.configured.size[1], 'request ' + pair.name + ' width is set to ' + pair.configured.size[1]); + assert.equal(pair.sent.ext.siteID, pair.configured.params.siteID, 'request ' + pair.name + ' siteID is set to ' + pair.configured.params.siteID); + } + + assert.equal(sidMatched.unmatched.configured.length, unsupportedSizeCount, unsupportedSizeCount + ' of configured bids is missing in impression Obj'); + assert.equal(sidMatched.unmatched.configured[0].placementCode, invalidSlotPlacement, "missing slot's placement code is " + invalidSlotPlacement); + assert.equal(sidMatched.unmatched.configured[0].params.id, invalidSlotID, "missing slot's slotID is " + invalidSlotID); + + assert.equal(sidMatched.unmatched.sent.length, 0, 'All bids in impression object are from configured bids'); + }); + + it('test_prebid_indexAdapter_request_7: multiple sizes with slots that exceeds max threshold requests -> 1 Ad Server request with supported sizes only', function () { + var requestSlotNumber = SlotThreshold; + var requestSizeNumber = 2; + var configuredBids = IndexUtils.createBidSlots(requestSlotNumber, requestSizeNumber); + adapter.callBids({ bids: configuredBids }); + + assert.isTrue(adLoader.loadScript.called, 'loadScript get request'); + assert.include(adLoader.loadScript.firstCall.args[0], HeaderTagRequest, 'request is headertag request'); + + var requestJSON = IndexUtils.parseIndexRequest(adLoader.loadScript.firstCall.args[0]); + assert.isNotNull(requestJSON.r.imp, 'headertag request include impression object'); + + var impressionObj = requestJSON.r.imp; + + var expandedBids = configuredBids.map(bid => IndexUtils.expandSizes(bid)) + var sidMatched = IndexUtils.matchBidsOnSID(expandedBids, impressionObj); + + assert.equal(sidMatched.matched.length, requestSlotNumber * requestSizeNumber, 'All slots each with multiple sizes are in AS request'); + for (var i = 0; i < sidMatched.matched.length; i++) { + var pair = sidMatched.matched[i]; + assert.equal(pair.sent.banner.w, pair.configured.size[0], 'request ' + pair.name + ' width is set to ' + pair.configured.size[0]); + assert.equal(pair.sent.banner.h, pair.configured.size[1], 'request ' + pair.name + ' width is set to ' + pair.configured.size[1]); + assert.equal(pair.sent.ext.siteID, pair.configured.params.siteID, 'request ' + pair.name + ' siteID is set to ' + pair.configured.params.siteID); + } + + assert.equal(sidMatched.unmatched.configured.length, 0, 'All configured bids are in impression Obj'); + assert.equal(sidMatched.unmatched.sent.length, 0, 'All bids in impression object are from configured bids'); + }); + + it('test_prebid_indexAdapter_request_sizeID_1: 1 prebid size slot, 1 index slot with size -> one slot in AS request 1 no size ID', function () { + var slotID = 52; + var slotSizes = IndexUtils.supportedSizes[0]; + + var configuredBids = [ + IndexUtils.createBidSlot(IndexUtils.DefaultPlacementCodePrefix, slotID, [ slotSizes ], { slotSize: slotSizes }) + ]; + + adapter.callBids({ bids: configuredBids }); + + assert.isTrue(adLoader.loadScript.called, 'loadScript get request'); + + assert.include(adLoader.loadScript.firstCall.args[0], HeaderTagRequest, 'request is headertag request'); + + var requestJSON = IndexUtils.parseIndexRequest(adLoader.loadScript.firstCall.args[0]); + assert.isNotNull(requestJSON.r.imp, 'headertag request include impression object'); + + var impressionObj = requestJSON.r.imp; + + assert.equal(impressionObj.length, 1, '1 slot is made in the request'); + assert.equal(impressionObj[0].banner.w, slotSizes[0], 'the width made in the request matches with request: ' + slotSizes[0]); + assert.equal(impressionObj[0].banner.h, slotSizes[1], 'the height made in the request matches with request: ' + slotSizes[1]); + assert.equal(impressionObj[0].ext.sid, slotID, 'slotID in the request matches with configuration: ' + slotID); + assert.equal(impressionObj[0].ext.siteID, IndexUtils.DefaultSiteID, 'siteID in the request matches with request: ' + IndexUtils.DefaultSiteID); + }); + + it('test_prebid_indexAdapter_request_sizeID_2: multiple prebid size slot, 1 index slot with size -> one slot in AS request 1 no size ID', function () { + var slotID = 52; + var slotSizes = IndexUtils.supportedSizes[0]; + + var configuredBids = [ + IndexUtils.createBidSlot(IndexUtils.DefaultPlacementCodePrefix, slotID, [ slotSizes, IndexUtils.supportedSizes[1] ], { slotSize: slotSizes }) + ]; + + adapter.callBids({ bids: configuredBids }); + + assert.isTrue(adLoader.loadScript.called, 'loadScript get request'); + + assert.include(adLoader.loadScript.firstCall.args[0], HeaderTagRequest, 'request is headertag request'); + + var requestJSON = IndexUtils.parseIndexRequest(adLoader.loadScript.firstCall.args[0]); + assert.isNotNull(requestJSON.r.imp, 'headertag request include impression object'); + + var impressionObj = requestJSON.r.imp; + + assert.equal(impressionObj.length, 1, '1 slot is made in the request'); + assert.equal(impressionObj[0].banner.w, slotSizes[0], 'the width made in the request matches with request: ' + slotSizes[0]); + assert.equal(impressionObj[0].banner.h, slotSizes[1], 'the height made in the request matches with request: ' + slotSizes[1]); + assert.equal(impressionObj[0].ext.sid, slotID, 'slotID in the request matches with configuration: ' + slotID); + assert.equal(impressionObj[0].ext.siteID, IndexUtils.DefaultSiteID, 'siteID in the request matches with request: ' + IndexUtils.DefaultSiteID); + }); + + it('test_prebid_indexAdapter_request_sizeID_3: multiple prebid size slot, index slots with size for all prebid slots -> all size in AS request, no size ID', function () { + var slotID_1 = 52; + var slotID_2 = 53; + var slotSizes_1 = IndexUtils.supportedSizes[0]; + var slotSizes_2 = IndexUtils.supportedSizes[1]; + + var configuredBids = [ + IndexUtils.createBidSlot(IndexUtils.DefaultPlacementCodePrefix, slotID_1, [ slotSizes_1, slotSizes_2 ], { slotSize: slotSizes_1 }), + IndexUtils.createBidSlot(IndexUtils.DefaultPlacementCodePrefix, slotID_2, [ slotSizes_1, slotSizes_2 ], { slotSize: slotSizes_2 }) + ]; + + adapter.callBids({ bids: configuredBids }); + + assert.isTrue(adLoader.loadScript.called, 'loadScript get request'); + + assert.include(adLoader.loadScript.firstCall.args[0], HeaderTagRequest, 'request is headertag request'); + + var requestJSON = IndexUtils.parseIndexRequest(adLoader.loadScript.firstCall.args[0]); + assert.isNotNull(requestJSON.r.imp, 'headertag request include impression object'); + + var impressionObj = requestJSON.r.imp; + assert.equal(impressionObj.length, 2, '2 slot is made in the request'); + assert.equal(impressionObj[0].banner.w, slotSizes_1[0], 'the width made in the request matches with request: ' + slotSizes_1[0]); + assert.equal(impressionObj[0].banner.h, slotSizes_1[1], 'the height made in the request matches with request: ' + slotSizes_1[1]); + assert.equal(impressionObj[0].ext.sid, slotID_1, 'slotID in the request matches with configuration: ' + slotID_1); + assert.equal(impressionObj[0].ext.siteID, IndexUtils.DefaultSiteID, 'siteID in the request matches with request: ' + IndexUtils.DefaultSiteID); + + assert.equal(impressionObj[1].banner.w, slotSizes_2[0], 'the width made in the request matches with request: ' + slotSizes_2[0]); + assert.equal(impressionObj[1].banner.h, slotSizes_2[1], 'the height made in the request matches with request: ' + slotSizes_2[1]); + assert.equal(impressionObj[1].ext.sid, slotID_2, 'slotID in the request matches with configuration: ' + slotID_2); + assert.equal(impressionObj[1].ext.siteID, IndexUtils.DefaultSiteID, 'siteID in the request matches with request: ' + IndexUtils.DefaultSiteID); + }); + + it('test_prebid_indexAdapter_request_sizeID_4: multiple prebid size slot, 1 index slot but size not in prebid defined size git -> no AS requset', function () { + var slotID = 52; + var slotSizes = IndexUtils.unsupportedSizes[0]; + + var configuredBids = [ + IndexUtils.createBidSlot(IndexUtils.DefaultPlacementCodePrefix, slotID, [ IndexUtils.supportedSizes[0] ], { slotSize: slotSizes }) + ]; + + adapter.callBids({ bids: configuredBids }); + + assert.isUndefined(adLoader.loadScript.firstCall.args[0], 'no request made to AS'); + }); + + it('test_prebid_indexAdapter_request_sizeID_5: multiple prebid size slot, 1 index slot but size not defined in slot -> no AS requset', function () { + var slotID = 52; + var slotSizes = IndexUtils.supportedSizes[1]; + + var configuredBids = [ + IndexUtils.createBidSlot(IndexUtils.DefaultPlacementCodePrefix, slotID, [ IndexUtils.supportedSizes[0] ], { slotSize: slotSizes }) + ]; + + adapter.callBids({ bids: configuredBids }); + + assert.isUndefined(adLoader.loadScript.firstCall.args[0], 'no request made to AS'); + }); +}); diff --git a/test/spec/modules/indexExchangeBidAdapter_response_spec.js b/test/spec/modules/indexExchangeBidAdapter_response_spec.js new file mode 100644 index 00000000000..9285c6653be --- /dev/null +++ b/test/spec/modules/indexExchangeBidAdapter_response_spec.js @@ -0,0 +1,1170 @@ +import Adapter from '../../../modules/indexExchangeBidAdapter'; +import bidManager from '../../../src/bidmanager'; +import adLoader from '../../../src/adloader'; + +var assert = require('chai').assert; +var IndexUtils = require('../../helpers/index_adapter_utils.js'); +var HeaderTagRequest = '/cygnus'; +var SlotThreshold = 20; +var ADAPTER_CODE = 'indexExchange'; +var DefaultValue = { + dealID: 'IXDeal' +}; + +var ResponseStatus = { + noBid: 'Bid returned empty or error response' +}; + +describe('indexExchange adapter - Response', function () { + let adapter; + let sandbox; + + beforeEach(function() { + window._IndexRequestData = {}; + _IndexRequestData.impIDToSlotID = {}; + _IndexRequestData.reqOptions = {}; + _IndexRequestData.targetIDToResp = {}; + window.cygnus_index_args = {}; + + adapter = new Adapter(); + sandbox = sinon.sandbox.create(); + sandbox.stub(bidManager, 'addBidResponse'); + sandbox.stub(adLoader, 'loadScript'); + }); + + afterEach(function() { + sandbox.restore(); + }); + + it('test_prebid_indexAdapter_response_1_1: response for single slot with single size -> bid fetched into prebid', function () { + var configuredBids = IndexUtils.createBidSlots(1, 1); + adapter.callBids({ bids: configuredBids }); + + var requestJSON = IndexUtils.parseIndexRequest(adLoader.loadScript.firstCall.args[0]); + var asResponse = IndexUtils.getBidResponse(configuredBids, requestJSON); + cygnus_index_parse_res(asResponse); + + var expectedAdapterResponse = IndexUtils.getExpectedAdaptorResponse(configuredBids, asResponse); + + var adapterResponse = {}; + + for (var i = 0; i < bidManager.addBidResponse.callCount; i++) { + var adUnitCode = bidManager.addBidResponse.getCall(i).args[0]; + var bid = bidManager.addBidResponse.getCall(i).args[1]; + + if (typeof adapterResponse[adUnitCode] === 'undefined') { + adapterResponse[adUnitCode] = []; + }; + adapterResponse[adUnitCode].push(bid); + } + + var prebidResponsePair = IndexUtils.matchOnPlacementCode(expectedAdapterResponse, adapterResponse); + for (var i = 0; i < prebidResponsePair.matched.length; i++) { + var pair = prebidResponsePair.matched[i]; + assert.equal(pair.prebid.length, 1, 'Only one bid is ferched into prebid'); + assert.equal(pair.prebid[0].siteID, pair.expected[0].siteID, 'adapter response for ' + pair.placementCode + ' siteID is set to ' + pair.expected[0].siteID); + assert.equal(pair.prebid[0].bidderCode, pair.expected[0].bidderCode, 'adapter response for ' + pair.placementCode + ' bidderCode is set to ' + pair.expected[0].bidderCode); + assert.equal(pair.prebid[0].width, pair.expected[0].width, 'adapter response for ' + pair.placementCode + ' width is set to ' + pair.expected[0].width); + assert.equal(pair.prebid[0].height, pair.expected[0].height, 'adapter response for ' + pair.placementCode + ' height is set to ' + pair.expected[0].height); + assert.equal(pair.prebid[0].ad, pair.expected[0].ad, 'adapter response for ' + pair.placementCode + ' ad is set to ' + pair.expected[0].ad); + assert.equal(pair.prebid[0].cpm, pair.expected[0].cpm, 'adapter response for ' + pair.placementCode + ' cpm is set to ' + pair.expected[0].cpm); + } + + assert.equal(prebidResponsePair.unmatched.expected.length, 0, 'All AS bid response translated to Adapter response for prebid'); + assert.equal(prebidResponsePair.unmatched.prebid.length, 0, 'All Adapter response for prebid is from AS bid'); + }); + + it('test_prebid_indexAdapter_response_1_2: pass on bid for single slot with single size -> bid fetched into prebid', function () { + var configuredBids = [ + IndexUtils.createBidSlot(IndexUtils.DefaultPlacementCodePrefix, 'slot1', [ IndexUtils.supportedSizes[0] ]), + ]; + adapter.callBids({ bids: configuredBids }); + + var requestJSON = IndexUtils.parseIndexRequest(adLoader.loadScript.firstCall.args[0]); + var asResponse = IndexUtils.getBidResponse(configuredBids, requestJSON, undefined, undefined, [ [ true ] ]); + cygnus_index_parse_res(asResponse); + + var expectedAdapterResponse = IndexUtils.getExpectedAdaptorResponse(configuredBids, asResponse); + + var adapterResponse = {}; + + for (var i = 0; i < bidManager.addBidResponse.callCount; i++) { + var adUnitCode = bidManager.addBidResponse.getCall(i).args[0]; + var bid = bidManager.addBidResponse.getCall(i).args[1]; + + if (typeof adapterResponse[adUnitCode] === 'undefined') { + adapterResponse[adUnitCode] = []; + }; + adapterResponse[adUnitCode].push(bid); + } + + var prebidResponsePair = IndexUtils.matchOnPlacementCode(expectedAdapterResponse, adapterResponse); + + assert.equal(prebidResponsePair.matched.length, 0, 'No bids are added to prebid'); + assert.equal(prebidResponsePair.unmatched.expected.length, 0, 'All AS bid response translated to Adapter response for prebid'); + assert.equal(prebidResponsePair.unmatched.prebid.length, 1, 'no Adapter response for prebid is from AS bid'); + }); + + it('test_prebid_indexAdapter_response_2_1: response for single slot with multiple sizes -> all bids fetched into prebid', function () { + var configuredBids = IndexUtils.createBidSlots(1, 3); + adapter.callBids({ bids: configuredBids }); + + var requestJSON = IndexUtils.parseIndexRequest(adLoader.loadScript.firstCall.args[0]); + + var asResponse = IndexUtils.getBidResponse(configuredBids, requestJSON); + cygnus_index_parse_res(asResponse); + + var expectedAdapterResponse = IndexUtils.getExpectedAdaptorResponse(configuredBids, asResponse, [ [1000, 3000, 2000] ]); + + var adapterResponse = {}; + + for (var i = 0; i < bidManager.addBidResponse.callCount; i++) { + var adUnitCode = bidManager.addBidResponse.getCall(i).args[0]; + var bid = bidManager.addBidResponse.getCall(i).args[1]; + + if (typeof adapterResponse[adUnitCode] === 'undefined') { + adapterResponse[adUnitCode] = []; + }; + adapterResponse[adUnitCode].push(bid); + } + + var prebidResponsePair = IndexUtils.matchOnPlacementCode(expectedAdapterResponse, adapterResponse); + + for (var i = 0; i < prebidResponsePair.matched.length; i++) { + var pair = prebidResponsePair.matched[i]; + + assert.equal(pair.prebid.length, 3, 'all bids are fetched into prebid'); + for (var j = 0; j < pair.prebid.length; j++) { + assert.equal(pair.prebid[j].siteID, pair.expected[j].siteID, 'adapter response for ' + pair.placementCode + ' siteID is set to ' + pair.expected[j].siteID); + assert.equal(pair.prebid[j].bidderCode, pair.expected[j].bidderCode, 'adapter response for ' + pair.placementCode + ' bidderCode is set to ' + pair.expected[j].bidderCode); + assert.equal(pair.prebid[j].width, pair.expected[j].width, 'adapter response for ' + pair.placementCode + ' width is set to ' + pair.expected[j].width); + assert.equal(pair.prebid[j].height, pair.expected[j].height, 'adapter response for ' + pair.placementCode + ' height is set to ' + pair.expected[j].height); + assert.equal(pair.prebid[j].ad, pair.expected[j].ad, 'adapter response for ' + pair.placementCode + ' ad is set to ' + pair.expected[j].ad); + assert.equal(pair.prebid[j].cpm, pair.expected[j].cpm, 'adapter response for ' + pair.placementCode + ' cpm is set to ' + pair.expected[j].cpm); + } + } + + assert.equal(prebidResponsePair.unmatched.expected.length, 0, 'All AS bid response translated to Adapter response for prebid'); + assert.equal(prebidResponsePair.unmatched.prebid.length, 0, 'All Adapter response for prebid is from AS bid'); + }); + + it('test_prebid_indexAdapter_response_2_2: pass on bid on some sizes for single slot with multiple sizes -> highest bid fetched into prebid', function () { + var configuredBids = [ + IndexUtils.createBidSlot(IndexUtils.DefaultPlacementCodePrefix, 'slot1', [ IndexUtils.supportedSizes[0], IndexUtils.supportedSizes[1] ]), + ]; + adapter.callBids({ bids: configuredBids }); + + var requestJSON = IndexUtils.parseIndexRequest(adLoader.loadScript.firstCall.args[0]); + + // pass on bid on second size + var asResponse = IndexUtils.getBidResponse(configuredBids, requestJSON, undefined, undefined, [ [ false, true ] ]); + cygnus_index_parse_res(asResponse); + + var expectedAdapterResponse = IndexUtils.getExpectedAdaptorResponse(configuredBids, asResponse); + + var adapterResponse = {}; + + for (var i = 0; i < bidManager.addBidResponse.callCount; i++) { + var adUnitCode = bidManager.addBidResponse.getCall(i).args[0]; + var bid = bidManager.addBidResponse.getCall(i).args[1]; + + if (typeof adapterResponse[adUnitCode] === 'undefined') { + adapterResponse[adUnitCode] = []; + }; + adapterResponse[adUnitCode].push(bid); + } + + var prebidResponsePair = IndexUtils.matchOnPlacementCode(expectedAdapterResponse, adapterResponse); + + assert.equal(prebidResponsePair.matched.length, 1, 'one slot is added to prebid'); + var pair = prebidResponsePair.matched[0]; + assert.equal(pair.prebid[0].siteID, pair.expected[0].siteID, 'adapter response for ' + pair.placementCode + ' siteID is set to ' + pair.expected[0].siteID); + assert.equal(pair.prebid[0].bidderCode, pair.expected[0].bidderCode, 'adapter response for ' + pair.placementCode + ' bidderCode is set to ' + pair.expected[0].bidderCode); + assert.equal(pair.prebid[0].width, pair.expected[0].width, 'adapter response for ' + pair.placementCode + ' width is set to ' + pair.expected[0].width); + assert.equal(pair.prebid[0].height, pair.expected[0].height, 'adapter response for ' + pair.placementCode + ' height is set to ' + pair.expected[0].height); + assert.equal(pair.prebid[0].ad, pair.expected[0].ad, 'adapter response for ' + pair.placementCode + ' ad is set to ' + pair.expected[0].ad); + assert.equal(pair.prebid[0].cpm, pair.expected[0].cpm, 'adapter response for ' + pair.placementCode + ' cpm is set to ' + pair.expected[0].cpm); + + assert.equal(prebidResponsePair.unmatched.expected.length, 0, 'All AS bid response translated to Adapter response for prebid'); + assert.equal(prebidResponsePair.unmatched.prebid.length, 0, 'All Adapter response for prebid is from AS bid'); + }); + + it('test_prebid_indexAdapter_response_2_3: pass on bid on all sizes for a single slot -> no bids fetched into prebid', function () { + var configuredBids = [ + IndexUtils.createBidSlot(IndexUtils.DefaultPlacementCodePrefix, 'slot1', [ IndexUtils.supportedSizes[0], IndexUtils.supportedSizes[1] ]), + ]; + adapter.callBids({ bids: configuredBids }); + + var requestJSON = IndexUtils.parseIndexRequest(adLoader.loadScript.firstCall.args[0]); + + // pass on bid on all bids + var asResponse = IndexUtils.getBidResponse(configuredBids, requestJSON, undefined, undefined, [ [ true, true ] ]); + cygnus_index_parse_res(asResponse); + + var expectedAdapterResponse = IndexUtils.getExpectedAdaptorResponse(configuredBids, asResponse); + + var adapterResponse = {}; + + for (var i = 0; i < bidManager.addBidResponse.callCount; i++) { + var adUnitCode = bidManager.addBidResponse.getCall(i).args[0]; + var bid = bidManager.addBidResponse.getCall(i).args[1]; + + if (typeof adapterResponse[adUnitCode] === 'undefined') { + adapterResponse[adUnitCode] = []; + }; + adapterResponse[adUnitCode].push(bid); + } + + var prebidResponsePair = IndexUtils.matchOnPlacementCode(expectedAdapterResponse, adapterResponse); + + assert.equal(prebidResponsePair.matched.length, 0, 'no bids fetched into prebid'); + assert.equal(prebidResponsePair.unmatched.expected.length, 0, 'All AS bid response translated to Adapter response for prebid'); + assert.equal(prebidResponsePair.unmatched.prebid[0][0].statusMessage, ResponseStatus.noBid, 'Bid response status is set to ' + ResponseStatus.noBid); + }); + + it('test_prebid_indexAdapter_response_3_1: response for multiple slots request with single size for each slots -> all response for all adunit fetched into prebid', function () { + var configuredBids = IndexUtils.createBidSlots(20); + adapter.callBids({ bids: configuredBids }); + + var requestJSON = IndexUtils.parseIndexRequest(adLoader.loadScript.firstCall.args[0]); + + var asResponse = IndexUtils.getBidResponse(configuredBids, requestJSON); + cygnus_index_parse_res(asResponse); + + var expectedAdapterResponse = IndexUtils.getExpectedAdaptorResponse(configuredBids, asResponse, [ [1000, 3000, 2000] ]); + + var adapterResponse = {}; + + for (var i = 0; i < bidManager.addBidResponse.callCount; i++) { + var adUnitCode = bidManager.addBidResponse.getCall(i).args[0]; + var bid = bidManager.addBidResponse.getCall(i).args[1]; + + if (typeof adapterResponse[adUnitCode] === 'undefined') { + adapterResponse[adUnitCode] = []; + }; + adapterResponse[adUnitCode].push(bid); + } + + var prebidResponsePair = IndexUtils.matchOnPlacementCode(expectedAdapterResponse, adapterResponse); + + for (var i = 0; i < prebidResponsePair.matched.length; i++) { + var pair = prebidResponsePair.matched[i]; + + assert.equal(pair.prebid.length, 1, 'all bids are fetched into prebid'); + assert.equal(pair.prebid[0].siteID, pair.expected[0].siteID, 'adapter response for ' + pair.placementCode + ' siteID is set to ' + pair.expected[0].siteID); + assert.equal(pair.prebid[0].bidderCode, pair.expected[0].bidderCode, 'adapter response for ' + pair.placementCode + ' bidderCode is set to ' + pair.expected[0].bidderCode); + assert.equal(pair.prebid[0].width, pair.expected[0].width, 'adapter response for ' + pair.placementCode + ' width is set to ' + pair.expected[0].width); + assert.equal(pair.prebid[0].height, pair.expected[0].height, 'adapter response for ' + pair.placementCode + ' height is set to ' + pair.expected[0].height); + assert.equal(pair.prebid[0].ad, pair.expected[0].ad, 'adapter response for ' + pair.placementCode + ' ad is set to ' + pair.expected[0].ad); + assert.equal(pair.prebid[0].cpm, pair.expected[0].cpm, 'adapter response for ' + pair.placementCode + ' cpm is set to ' + pair.expected[0].cpm); + } + + assert.equal(prebidResponsePair.unmatched.expected.length, 0, 'All AS bid response translated to Adapter response for prebid'); + assert.equal(prebidResponsePair.unmatched.prebid.length, 0, 'All Adapter response for prebid is from AS bid'); + }); + + it('test_prebid_indexAdapter_response_3_2: some slots response returned -> returned bids fetched into prebid ', function () { + var configuredBids = IndexUtils.createBidSlots(2); + adapter.callBids({ bids: configuredBids }); + + var requestJSON = IndexUtils.parseIndexRequest(adLoader.loadScript.firstCall.args[0]); + + var passOnBid = [ + [ false ], // bids back on first slot + [ true ], // pass on bid on second slot + ]; + var asResponse = IndexUtils.getBidResponse(configuredBids, requestJSON, undefined, undefined, passOnBid); + cygnus_index_parse_res(asResponse); + + var expectedAdapterResponse = IndexUtils.getExpectedAdaptorResponse(configuredBids, asResponse, [ [1000, 3000, 2000] ]); + + var adapterResponse = {}; + + for (var i = 0; i < bidManager.addBidResponse.callCount; i++) { + var adUnitCode = bidManager.addBidResponse.getCall(i).args[0]; + var bid = bidManager.addBidResponse.getCall(i).args[1]; + + if (typeof adapterResponse[adUnitCode] === 'undefined') { + adapterResponse[adUnitCode] = []; + }; + adapterResponse[adUnitCode].push(bid); + } + + var prebidResponsePair = IndexUtils.matchOnPlacementCode(expectedAdapterResponse, adapterResponse); + + assert.equal(prebidResponsePair.matched.length, 1, '1 bid from ad server is fetched into prebid'); + for (var i = 0; i < prebidResponsePair.matched.length; i++) { + var pair = prebidResponsePair.matched[i]; + + assert.equal(pair.prebid.length, 1, 'all bids are fetched into prebid'); + assert.equal(pair.prebid[0].siteID, pair.expected[0].siteID, 'adapter response for ' + pair.placementCode + ' siteID is set to ' + pair.expected[0].siteID); + assert.equal(pair.prebid[0].bidderCode, pair.expected[0].bidderCode, 'adapter response for ' + pair.placementCode + ' bidderCode is set to ' + pair.expected[0].bidderCode); + assert.equal(pair.prebid[0].width, pair.expected[0].width, 'adapter response for ' + pair.placementCode + ' width is set to ' + pair.expected[0].width); + assert.equal(pair.prebid[0].height, pair.expected[0].height, 'adapter response for ' + pair.placementCode + ' height is set to ' + pair.expected[0].height); + assert.equal(pair.prebid[0].ad, pair.expected[0].ad, 'adapter response for ' + pair.placementCode + ' ad is set to ' + pair.expected[0].ad); + assert.equal(pair.prebid[0].cpm, pair.expected[0].cpm, 'adapter response for ' + pair.placementCode + ' cpm is set to ' + pair.expected[0].cpm); + } + + assert.equal(prebidResponsePair.unmatched.expected.length, 0, 'All AS bid response translated to Adapter response for prebid'); + assert.equal(prebidResponsePair.unmatched.prebid.length, 1, 'One slot passed on bid from Ad Server'); + }); + + it('test_prebid_indexAdapter_response_3_3: response for multiple slots with no response returned -> no bid fetched into prebid', function () { + var configuredBids = IndexUtils.createBidSlots(2); + adapter.callBids({ bids: configuredBids }); + + var requestJSON = IndexUtils.parseIndexRequest(adLoader.loadScript.firstCall.args[0]); + + var passOnBid = [ + [ true ], // pass on bid on the first slot + [ true ], // pass on bid on the second slot + ]; + var asResponse = IndexUtils.getBidResponse(configuredBids, requestJSON, undefined, undefined, passOnBid); + cygnus_index_parse_res(asResponse); + + var expectedAdapterResponse = IndexUtils.getExpectedAdaptorResponse(configuredBids, asResponse, [ [1000, 3000, 2000] ]); + + var adapterResponse = {}; + + for (var i = 0; i < bidManager.addBidResponse.callCount; i++) { + var adUnitCode = bidManager.addBidResponse.getCall(i).args[0]; + var bid = bidManager.addBidResponse.getCall(i).args[1]; + + if (typeof adapterResponse[adUnitCode] === 'undefined') { + adapterResponse[adUnitCode] = []; + }; + adapterResponse[adUnitCode].push(bid); + } + + var prebidResponsePair = IndexUtils.matchOnPlacementCode(expectedAdapterResponse, adapterResponse); + + assert.equal(prebidResponsePair.matched.length, 0, 'no bids from ad server is fetched into prebid'); + + assert.equal(prebidResponsePair.unmatched.expected.length, 0, 'All AS bid response translated to Adapter response for prebid'); + assert.equal(prebidResponsePair.unmatched.prebid.length, 2, 'two slots passed on bid from Ad Server'); + }); + + it("test_prebid_indexAdapter_refreshSlot_1: slot refreshes multiple times with different bids on refresh with same price -> response to prebid use correct AS response's creative", function () { + var configuredBids = IndexUtils.createBidSlots(1, 1); + + var refreshSetup = [ {price: 1000, request: 'request-1'}, {price: 1000, request: 'request-2'} ]; + for (var i = 0; i < refreshSetup.length; i++) { + var requestParams = refreshSetup[i]; + + adapter.callBids({ bids: configuredBids }); + var requestJSON = IndexUtils.parseIndexRequest(adLoader.loadScript.firstCall.args[0]); + + // first ix call + var asResponse = IndexUtils.getBidResponse(configuredBids, requestJSON, [ [requestParams.price] ], requestParams.request); + cygnus_index_parse_res(asResponse); + var expectedAdapterResponse = IndexUtils.getExpectedAdaptorResponse(configuredBids, asResponse); + + var adapterResponse = {}; + + for (var i = 0; i < bidManager.addBidResponse.callCount; i++) { + var adUnitCode = bidManager.addBidResponse.getCall(i).args[0]; + var bid = bidManager.addBidResponse.getCall(i).args[1]; + + if (typeof adapterResponse[adUnitCode] === 'undefined') { + adapterResponse[adUnitCode] = []; + }; + adapterResponse[adUnitCode].push(bid); + } + + var prebidResponsePair = IndexUtils.matchOnPlacementCode(expectedAdapterResponse, adapterResponse); + + for (var j = 0; j < prebidResponsePair.matched.length; j++) { + var pair = prebidResponsePair.matched[j]; + + assert.equal(pair.prebid.length, 1, 'all bids are fetched into prebid'); + for (var k = 0; k < pair.prebid.length; k++) { + assert.equal(pair.prebid[k].siteID, pair.expected[k].siteID, 'adapter response for ' + pair.placementCode + ' siteID is set to ' + pair.expected[k].siteID); + assert.equal(pair.prebid[k].bidderCode, pair.expected[k].bidderCode, 'adapter response for ' + pair.placementCode + ' bidderCode is set to ' + pair.expected[k].bidderCode); + assert.equal(pair.prebid[k].width, pair.expected[k].width, 'adapter response for ' + pair.placementCode + ' width is set to ' + pair.expected[k].width); + assert.equal(pair.prebid[k].height, pair.expected[k].height, 'adapter response for ' + pair.placementCode + ' height is set to ' + pair.expected[k].height); + assert.equal(pair.prebid[k].ad, pair.expected[k].ad, 'adapter response for ' + pair.placementCode + ' ad is set to ' + pair.expected[k].ad); + assert.equal(pair.prebid[k].cpm, pair.expected[k].cpm, 'adapter response for ' + pair.placementCode + ' cpm is set to ' + pair.expected[k].cpm); + } + } + + assert.equal(prebidResponsePair.unmatched.expected.length, 0, 'All AS bid response translated to Adapter response for prebid'); + assert.equal(prebidResponsePair.unmatched.prebid.length, 0, 'All Adapter response for prebid is from AS bid'); + + bidManager.addBidResponse.reset(); + adapterResponse = {}; // initialize adapterReaponse for refresh test + } + }); + + it("test_prebid_indexAdapter_refreshSlot_2: slot refreshes multiple times with different bids on refresh with different price, but first bid is higher -> response to prebid use correct AS response's creative", function () { + var configuredBids = IndexUtils.createBidSlots(1, 1); + + var refreshSetup = [ {price: 8000, request: 'request-1'}, {price: 1000, request: 'request-2'} ]; + for (var i = 0; i < refreshSetup.length; i++) { + var requestParams = refreshSetup[i]; + + adapter.callBids({ bids: configuredBids }); + var requestJSON = IndexUtils.parseIndexRequest(adLoader.loadScript.firstCall.args[0]); + + // first ix call + var asResponse = IndexUtils.getBidResponse(configuredBids, requestJSON, [ [requestParams.price] ], requestParams.request); + cygnus_index_parse_res(asResponse); + + var expectedAdapterResponse = IndexUtils.getExpectedAdaptorResponse(configuredBids, asResponse); + + var adapterResponse = {}; + + for (var i = 0; i < bidManager.addBidResponse.callCount; i++) { + var adUnitCode = bidManager.addBidResponse.getCall(i).args[0]; + var bid = bidManager.addBidResponse.getCall(i).args[1]; + + if (typeof adapterResponse[adUnitCode] === 'undefined') { + adapterResponse[adUnitCode] = []; + }; + adapterResponse[adUnitCode].push(bid); + } + + var prebidResponsePair = IndexUtils.matchOnPlacementCode(expectedAdapterResponse, adapterResponse); + + for (var j = 0; j < prebidResponsePair.matched.length; j++) { + var pair = prebidResponsePair.matched[j]; + + assert.equal(pair.prebid.length, 1, 'all bids are fetched into prebid'); + for (var k = 0; k < pair.prebid.length; k++) { + assert.equal(pair.prebid[k].siteID, pair.expected[k].siteID, 'adapter response for ' + pair.placementCode + ' siteID is set to ' + pair.expected[k].siteID); + assert.equal(pair.prebid[k].bidderCode, pair.expected[k].bidderCode, 'adapter response for ' + pair.placementCode + ' bidderCode is set to ' + pair.expected[k].bidderCode); + assert.equal(pair.prebid[k].width, pair.expected[k].width, 'adapter response for ' + pair.placementCode + ' width is set to ' + pair.expected[k].width); + assert.equal(pair.prebid[k].height, pair.expected[k].height, 'adapter response for ' + pair.placementCode + ' height is set to ' + pair.expected[k].height); + assert.equal(pair.prebid[k].ad, pair.expected[k].ad, 'adapter response for ' + pair.placementCode + ' ad is set to ' + pair.expected[k].ad); + assert.equal(pair.prebid[k].cpm, pair.expected[k].cpm, 'adapter response for ' + pair.placementCode + ' cpm is set to ' + pair.expected[k].cpm); + } + } + + assert.equal(prebidResponsePair.unmatched.expected.length, 0, 'All AS bid response translated to Adapter response for prebid'); + assert.equal(prebidResponsePair.unmatched.prebid.length, 0, 'All Adapter response for prebid is from AS bid'); + bidManager.addBidResponse.reset(); + adapterResponse = {}; // initialize adapterReaponse for refresh test + } + }); + + it("test_prebid_indexAdapter_refreshSlot_3: slot refreshes multiple times with different bids on refresh with different price, but first bid is lower -> response to prebid use correct AS response's creative", function () { + var configuredBids = IndexUtils.createBidSlots(1, 1); + + var refreshSetup = [ {price: 1000, request: 'request-1'}, {price: 8000, request: 'request-2'} ]; + for (var i = 0; i < refreshSetup.length; i++) { + var requestParams = refreshSetup[i]; + + adapter.callBids({ bids: configuredBids }); + var requestJSON = IndexUtils.parseIndexRequest(adLoader.loadScript.firstCall.args[0]); + + // first ix call + var asResponse = IndexUtils.getBidResponse(configuredBids, requestJSON, [ [requestParams.price] ], requestParams.request); + cygnus_index_parse_res(asResponse); + + var expectedAdapterResponse = IndexUtils.getExpectedAdaptorResponse(configuredBids, asResponse); + + var adapterResponse = {}; + + for (var i = 0; i < bidManager.addBidResponse.callCount; i++) { + var adUnitCode = bidManager.addBidResponse.getCall(i).args[0]; + var bid = bidManager.addBidResponse.getCall(i).args[1]; + + if (typeof adapterResponse[adUnitCode] === 'undefined') { + adapterResponse[adUnitCode] = []; + }; + adapterResponse[adUnitCode].push(bid); + } + + var prebidResponsePair = IndexUtils.matchOnPlacementCode(expectedAdapterResponse, adapterResponse); + + for (var j = 0; j < prebidResponsePair.matched.length; j++) { + var pair = prebidResponsePair.matched[j]; + + assert.equal(pair.prebid.length, 1, 'all bids are fetched into prebid'); + for (var k = 0; k < pair.prebid.length; k++) { + assert.equal(pair.prebid[k].siteID, pair.expected[k].siteID, 'adapter response for ' + pair.placementCode + ' siteID is set to ' + pair.expected[k].siteID); + assert.equal(pair.prebid[k].bidderCode, pair.expected[k].bidderCode, 'adapter response for ' + pair.placementCode + ' bidderCode is set to ' + pair.expected[k].bidderCode); + assert.equal(pair.prebid[k].width, pair.expected[k].width, 'adapter response for ' + pair.placementCode + ' width is set to ' + pair.expected[k].width); + assert.equal(pair.prebid[k].height, pair.expected[k].height, 'adapter response for ' + pair.placementCode + ' height is set to ' + pair.expected[k].height); + assert.equal(pair.prebid[k].ad, pair.expected[k].ad, 'adapter response for ' + pair.placementCode + ' ad is set to ' + pair.expected[k].ad); + assert.equal(pair.prebid[k].cpm, pair.expected[k].cpm, 'adapter response for ' + pair.placementCode + ' cpm is set to ' + pair.expected[k].cpm); + } + } + + assert.equal(prebidResponsePair.unmatched.expected.length, 0, 'All AS bid response translated to Adapter response for prebid'); + assert.equal(prebidResponsePair.unmatched.prebid.length, 0, 'All Adapter response for prebid is from AS bid'); + bidManager.addBidResponse.reset(); + adapterResponse = {}; // initialize adapterReaponse for refresh test + } + }); + + it('test_prebid_indexAdapter_refreshSlot_4: got no response the second time -> no bids fetched into prebid', function () { + var configuredBids = IndexUtils.createBidSlots(1, 1); + + var refreshSetup = [ { price: 1000, request: 'request-1', passOnBid: false}, { price: 1000, request: 'request-2', passOnBid: true} ]; + for (var i = 0; i < refreshSetup.length; i++) { + var requestParams = refreshSetup[i]; + + adapter.callBids({ bids: configuredBids }); + var requestJSON = IndexUtils.parseIndexRequest(adLoader.loadScript.firstCall.args[0]); + + // first ix call + var asResponse = IndexUtils.getBidResponse(configuredBids, requestJSON, [ [requestParams.price] ], requestParams.request, [ [ requestParams.passOnBid ] ]); + cygnus_index_parse_res(asResponse); + var expectedAdapterResponse = IndexUtils.getExpectedAdaptorResponse(configuredBids, asResponse); + + var adapterResponse = {}; + + for (var i = 0; i < bidManager.addBidResponse.callCount; i++) { + var adUnitCode = bidManager.addBidResponse.getCall(i).args[0]; + var bid = bidManager.addBidResponse.getCall(i).args[1]; + + if (typeof adapterResponse[adUnitCode] === 'undefined') { + adapterResponse[adUnitCode] = []; + }; + adapterResponse[adUnitCode].push(bid); + } + + var prebidResponsePair = IndexUtils.matchOnPlacementCode(expectedAdapterResponse, adapterResponse); + + for (var j = 0; j < prebidResponsePair.matched.length; j++) { + var pair = prebidResponsePair.matched[j]; + + assert.equal(pair.prebid.length, 1, 'all bids are fetched into prebid'); + for (var k = 0; k < pair.prebid.length; k++) { + assert.equal(pair.prebid[k].siteID, pair.expected[k].siteID, 'adapter response for ' + pair.placementCode + ' siteID is set to ' + pair.expected[k].siteID); + assert.equal(pair.prebid[k].bidderCode, pair.expected[k].bidderCode, 'adapter response for ' + pair.placementCode + ' bidderCode is set to ' + pair.expected[k].bidderCode); + assert.equal(pair.prebid[k].width, pair.expected[k].width, 'adapter response for ' + pair.placementCode + ' width is set to ' + pair.expected[k].width); + assert.equal(pair.prebid[k].height, pair.expected[k].height, 'adapter response for ' + pair.placementCode + ' height is set to ' + pair.expected[k].height); + assert.equal(pair.prebid[k].ad, pair.expected[k].ad, 'adapter response for ' + pair.placementCode + ' ad is set to ' + pair.expected[k].ad); + assert.equal(pair.prebid[k].cpm, pair.expected[k].cpm, 'adapter response for ' + pair.placementCode + ' cpm is set to ' + pair.expected[k].cpm); + } + } + assert.equal(prebidResponsePair.unmatched.expected.length, 0, 'All AS bid response translated to Adapter response for prebid'); + if (requestParams.passOnBid) { + assert.equal(prebidResponsePair.unmatched.prebid.length, 1, '1 Adapter response is missing'); + } else { + assert.equal(prebidResponsePair.unmatched.prebid.length, 0, 'All Adapter response for prebid is from AS bid'); + } + + bidManager.addBidResponse.reset(); + adapterResponse = {}; // initialize adapterReaponse for refresh test + } + }); + + it('test_prebid_indexAdapter_refreshSlot_5: unsupported slots refresh -> no ad server request, no bids fetched into prebid', function () { + var configuredBids = [ + IndexUtils.createBidSlot(IndexUtils.DefaultPlacementCodePrefix, 'slot_1', [ IndexUtils.unsupportedSizes[0] ]) + ]; + + var refreshSetup = [ { request: 'request-1' }, { request: 'request-2' } ]; + for (var i = 0; i < refreshSetup.length; i++) { + var requestParams = refreshSetup[i]; + + adapter.callBids({ bids: configuredBids }); + assert.isUndefined(adLoader.loadScript.firstCall.args[0], 'no ad server request for ' + requestParams.request) + } + }); + + it('test_prebid_indexAdapter_response_deal_1_1: response for single slot with single size contains alpha deal -> bid fetched into prebid', function () { + var configuredBids = IndexUtils.createBidSlots(1, 1); + adapter.callBids({ bids: configuredBids }); + + var requestJSON = IndexUtils.parseIndexRequest(adLoader.loadScript.firstCall.args[0]); + var optionalResponseParam = [ + [ + { ext: { dealid: 'ixDeal' } } // first slot first size + ] + ]; + var asResponse = IndexUtils.getBidResponse(configuredBids, requestJSON, undefined, undefined, undefined, optionalResponseParam); + cygnus_index_parse_res(asResponse); + + var expectedAdapterResponse = IndexUtils.getExpectedAdaptorResponse(configuredBids, asResponse); + + var adapterResponse = {}; + + for (var i = 0; i < bidManager.addBidResponse.callCount; i++) { + var adUnitCode = bidManager.addBidResponse.getCall(i).args[0]; + var bid = bidManager.addBidResponse.getCall(i).args[1]; + + if (typeof adapterResponse[adUnitCode] === 'undefined') { + adapterResponse[adUnitCode] = []; + }; + adapterResponse[adUnitCode].push(bid); + } + + var prebidResponsePair = IndexUtils.matchOnPlacementCode(expectedAdapterResponse, adapterResponse); + for (var i = 0; i < prebidResponsePair.matched.length; i++) { + var pair = prebidResponsePair.matched[i]; + + assert.equal(pair.prebid[i].siteID, pair.expected[i].siteID, 'adapter response for ' + pair.placementCode + ' siteID is set to ' + pair.expected[i].siteID); + assert.equal(pair.prebid[i].bidderCode, pair.expected[i].bidderCode, 'adapter response for ' + pair.placementCode + ' bidderCode is set to ' + pair.expected[i].bidderCode); + assert.equal(pair.prebid[i].width, pair.expected[i].width, 'adapter response for ' + pair.placementCode + ' width is set to ' + pair.expected[i].width); + assert.equal(pair.prebid[i].height, pair.expected[i].height, 'adapter response for ' + pair.placementCode + ' height is set to ' + pair.expected[i].height); + assert.equal(pair.prebid[i].ad, pair.expected[i].ad, 'adapter response for ' + pair.placementCode + ' ad is set to ' + pair.expected[i].ad); + assert.equal(pair.prebid[i].cpm, pair.expected[i].cpm, 'adapter response for ' + pair.placementCode + ' cpm is set to ' + pair.expected[i].cpm); + assert.equal(pair.prebid[i].dealId, pair.expected[i].dealId, 'adapter response for ' + pair.placementCode + ' deaiid is set to ' + pair.expected[i].dealId); + } + + assert.equal(prebidResponsePair.unmatched.expected.length, 0, 'All AS bid response translated to Adapter response for prebid'); + assert.equal(prebidResponsePair.unmatched.prebid.length, 0, 'All Adapter response for prebid is from AS bid'); + }); + + it('test_prebid_indexAdapter_response_deal_1_2: response for single slot with single size contains numeric deal -> bid fetched into prebid', function () { + var configuredBids = IndexUtils.createBidSlots(1, 1); + adapter.callBids({ bids: configuredBids }); + + var requestJSON = IndexUtils.parseIndexRequest(adLoader.loadScript.firstCall.args[0]); + var optionalResponseParam = [ + [ + { ext: { dealid: '239' } } // first slot first size + ] + ]; + var asResponse = IndexUtils.getBidResponse(configuredBids, requestJSON, undefined, undefined, undefined, optionalResponseParam); + cygnus_index_parse_res(asResponse); + var expectedAdapterResponse = IndexUtils.getExpectedAdaptorResponse(configuredBids, asResponse); + + var adapterResponse = {}; + + for (var i = 0; i < bidManager.addBidResponse.callCount; i++) { + var adUnitCode = bidManager.addBidResponse.getCall(i).args[0]; + var bid = bidManager.addBidResponse.getCall(i).args[1]; + + if (typeof adapterResponse[adUnitCode] === 'undefined') { + adapterResponse[adUnitCode] = []; + }; + adapterResponse[adUnitCode].push(bid); + } + + var prebidResponsePair = IndexUtils.matchOnPlacementCode(expectedAdapterResponse, adapterResponse); + + for (var i = 0; i < prebidResponsePair.matched.length; i++) { + var pair = prebidResponsePair.matched[i]; + + assert.equal(pair.prebid[i].siteID, pair.expected[i].siteID, 'adapter response for ' + pair.placementCode + ' siteID is set to ' + pair.expected[i].siteID); + assert.equal(pair.prebid[i].bidderCode, pair.expected[i].bidderCode, 'adapter response for ' + pair.placementCode + ' bidderCode is set to ' + pair.expected[i].bidderCode); + assert.equal(pair.prebid[i].width, pair.expected[i].width, 'adapter response for ' + pair.placementCode + ' width is set to ' + pair.expected[i].width); + assert.equal(pair.prebid[i].height, pair.expected[i].height, 'adapter response for ' + pair.placementCode + ' height is set to ' + pair.expected[i].height); + assert.equal(pair.prebid[i].ad, pair.expected[i].ad, 'adapter response for ' + pair.placementCode + ' ad is set to ' + pair.expected[i].ad); + assert.equal(pair.prebid[i].cpm, pair.expected[i].cpm, 'adapter response for ' + pair.placementCode + ' cpm is set to ' + pair.expected[i].cpm); + assert.equal(pair.prebid[i].dealId, pair.expected[i].dealId, 'adapter response for ' + pair.placementCode + ' deaiid is set to ' + pair.expected[i].dealId); + } + + assert.equal(prebidResponsePair.unmatched.expected.length, 0, 'All AS bid response translated to Adapter response for prebid'); + assert.equal(prebidResponsePair.unmatched.prebid.length, 0, 'All Adapter response for prebid is from AS bid'); + }); + + it('test_prebid_indexAdapter_response_deal_1_3: response for single slot with single size contains alpha-numeric deal starting with numeric -> bid fetched into prebid', function () { + var configuredBids = IndexUtils.createBidSlots(1, 1); + adapter.callBids({ bids: configuredBids }); + + var requestJSON = IndexUtils.parseIndexRequest(adLoader.loadScript.firstCall.args[0]); + var optionalResponseParam = [ + [ + { ext: { dealid: '1234Deal' } } // first slot first size + ] + ]; + var asResponse = IndexUtils.getBidResponse(configuredBids, requestJSON, undefined, undefined, undefined, optionalResponseParam); + cygnus_index_parse_res(asResponse); + var expectedAdapterResponse = IndexUtils.getExpectedAdaptorResponse(configuredBids, asResponse); + + var adapterResponse = {}; + + for (var i = 0; i < bidManager.addBidResponse.callCount; i++) { + var adUnitCode = bidManager.addBidResponse.getCall(i).args[0]; + var bid = bidManager.addBidResponse.getCall(i).args[1]; + + if (typeof adapterResponse[adUnitCode] === 'undefined') { + adapterResponse[adUnitCode] = []; + }; + adapterResponse[adUnitCode].push(bid); + } + + var prebidResponsePair = IndexUtils.matchOnPlacementCode(expectedAdapterResponse, adapterResponse); + + for (var i = 0; i < prebidResponsePair.matched.length; i++) { + var pair = prebidResponsePair.matched[i]; + + assert.equal(pair.prebid[i].siteID, pair.expected[i].siteID, 'adapter response for ' + pair.placementCode + ' siteID is set to ' + pair.expected[i].siteID); + assert.equal(pair.prebid[i].bidderCode, pair.expected[i].bidderCode, 'adapter response for ' + pair.placementCode + ' bidderCode is set to ' + pair.expected[i].bidderCode); + assert.equal(pair.prebid[i].width, pair.expected[i].width, 'adapter response for ' + pair.placementCode + ' width is set to ' + pair.expected[i].width); + assert.equal(pair.prebid[i].height, pair.expected[i].height, 'adapter response for ' + pair.placementCode + ' height is set to ' + pair.expected[i].height); + assert.equal(pair.prebid[i].ad, pair.expected[i].ad, 'adapter response for ' + pair.placementCode + ' ad is set to ' + pair.expected[i].ad); + assert.equal(pair.prebid[i].cpm, pair.expected[i].cpm, 'adapter response for ' + pair.placementCode + ' cpm is set to ' + pair.expected[i].cpm); + assert.equal(pair.prebid[i].dealId, pair.expected[i].dealId, 'adapter response for ' + pair.placementCode + ' deaiid is set to ' + pair.expected[i].dealId); + } + + assert.equal(prebidResponsePair.unmatched.expected.length, 0, 'All AS bid response translated to Adapter response for prebid'); + assert.equal(prebidResponsePair.unmatched.prebid.length, 0, 'All Adapter response for prebid is from AS bid'); + }); + + it('test_prebid_indexAdapter_response_deal_1_4: response for single slot with single size contains alpha-numeric deal starting with non-numeric -> bid fetched into prebid ', function () { + var configuredBids = IndexUtils.createBidSlots(1, 1); + adapter.callBids({ bids: configuredBids }); + + var requestJSON = IndexUtils.parseIndexRequest(adLoader.loadScript.firstCall.args[0]); + var optionalResponseParam = [ + [ + { ext: { dealid: 'deal1234' } } // first slot first size + ] + ]; + var asResponse = IndexUtils.getBidResponse(configuredBids, requestJSON, undefined, undefined, undefined, optionalResponseParam); // Alpha numeric starting with non-numeric + cygnus_index_parse_res(asResponse); + var expectedAdapterResponse = IndexUtils.getExpectedAdaptorResponse(configuredBids, asResponse); + + var adapterResponse = {}; + + for (var i = 0; i < bidManager.addBidResponse.callCount; i++) { + var adUnitCode = bidManager.addBidResponse.getCall(i).args[0]; + var bid = bidManager.addBidResponse.getCall(i).args[1]; + + if (typeof adapterResponse[adUnitCode] === 'undefined') { + adapterResponse[adUnitCode] = []; + }; + adapterResponse[adUnitCode].push(bid); + } + + var prebidResponsePair = IndexUtils.matchOnPlacementCode(expectedAdapterResponse, adapterResponse); + + for (var i = 0; i < prebidResponsePair.matched.length; i++) { + var pair = prebidResponsePair.matched[i]; + + assert.equal(pair.prebid[i].siteID, pair.expected[i].siteID, 'adapter response for ' + pair.placementCode + ' siteID is set to ' + pair.expected[i].siteID); + assert.equal(pair.prebid[i].bidderCode, pair.expected[i].bidderCode, 'adapter response for ' + pair.placementCode + ' bidderCode is set to ' + pair.expected[i].bidderCode); + assert.equal(pair.prebid[i].width, pair.expected[i].width, 'adapter response for ' + pair.placementCode + ' width is set to ' + pair.expected[i].width); + assert.equal(pair.prebid[i].height, pair.expected[i].height, 'adapter response for ' + pair.placementCode + ' height is set to ' + pair.expected[i].height); + assert.equal(pair.prebid[i].ad, pair.expected[i].ad, 'adapter response for ' + pair.placementCode + ' ad is set to ' + pair.expected[i].ad); + assert.equal(pair.prebid[i].cpm, pair.expected[i].cpm, 'adapter response for ' + pair.placementCode + ' cpm is set to ' + pair.expected[i].cpm); + assert.equal(pair.prebid[i].dealId, pair.expected[i].dealId, 'adapter response for ' + pair.placementCode + ' deaiid is set to ' + pair.expected[i].dealId); + } + + assert.equal(prebidResponsePair.unmatched.expected.length, 0, 'All AS bid response translated to Adapter response for prebid'); + assert.equal(prebidResponsePair.unmatched.prebid.length, 0, 'All Adapter response for prebid is from AS bid'); + }); + + it('test_prebid_indexAdapter_response_deal_2_1: response for single slot with multi size, all deal bids returned -> all bid fetched into prebid as deal bid', function () { + var sizeCount = 2; + var configuredBids = IndexUtils.createBidSlots(1, sizeCount); + adapter.callBids({ bids: configuredBids }); + + var requestJSON = IndexUtils.parseIndexRequest(adLoader.loadScript.firstCall.args[0]); + var optionalResponseParam = [ + [ + { ext: { deal: 'deal1', dealid: 'ixDealID1', dealname: 'deal name 1' } }, // first slot first size + { ext: { deal: 'deal2', dealid: 'ixDealID2', dealname: 'deal name 2' } }, // first slot second size + ] + ]; + var asResponse = IndexUtils.getBidResponse(configuredBids, requestJSON, undefined, undefined, undefined, optionalResponseParam); + cygnus_index_parse_res(asResponse); + var expectedAdapterResponse = IndexUtils.getExpectedAdaptorResponse(configuredBids, asResponse); + + var adapterResponse = {}; + + for (var i = 0; i < bidManager.addBidResponse.callCount; i++) { + var adUnitCode = bidManager.addBidResponse.getCall(i).args[0]; + var bid = bidManager.addBidResponse.getCall(i).args[1]; + + if (typeof adapterResponse[adUnitCode] === 'undefined') { + adapterResponse[adUnitCode] = []; + }; + adapterResponse[adUnitCode].push(bid); + } + + var prebidResponsePair = IndexUtils.matchOnPlacementCode(expectedAdapterResponse, adapterResponse); + for (var i = 0; i < prebidResponsePair.matched.length; i++) { + var pair = prebidResponsePair.matched[i]; + + for (var j = 0; j < pair.expected.length; j++) { + assert.equal(pair.prebid[j].siteID, pair.expected[j].siteID, 'adapter response for ' + pair.placementCode + ' siteID is set to ' + pair.expected[i].siteID); + assert.equal(pair.prebid[j].bidderCode, pair.expected[j].bidderCode, 'adapter response for ' + pair.placementCode + ' bidderCode is set to ' + pair.expected[i].bidderCode); + assert.equal(pair.prebid[j].width, pair.expected[j].width, 'adapter response for ' + pair.placementCode + ' width is set to ' + pair.expected[i].width); + assert.equal(pair.prebid[j].height, pair.expected[j].height, 'adapter response for ' + pair.placementCode + ' height is set to ' + pair.expected[i].height); + assert.equal(pair.prebid[j].ad, pair.expected[j].ad, 'adapter response for ' + pair.placementCode + ' ad is set to ' + pair.expected[i].ad); + assert.equal(pair.prebid[j].cpm, pair.expected[j].cpm, 'adapter response for ' + pair.placementCode + ' cpm is set to ' + pair.expected[i].cpm); + assert.equal(pair.prebid[j].dealId, pair.expected[j].dealId, 'adapter response for ' + pair.placementCode + ' deaiid is set to ' + pair.expected[i].dealId); + } + } + assert.equal(prebidResponsePair.unmatched.expected.length, 0, 'All AS bid response translated to Adapter response for prebid'); + assert.equal(prebidResponsePair.unmatched.prebid.length, 0, 'All Adapter response for prebid is from AS bid'); + }); + + it('test_prebid_indexAdapter_response_deal_2_2: response for single slot with multi size, some deal resposne returned and the rest non deal response -> all bid fetched, only deal response has dealID', function () { + var sizeCount = 2; + var configuredBids = IndexUtils.createBidSlots(1, sizeCount); + adapter.callBids({ bids: configuredBids }); + + var requestJSON = IndexUtils.parseIndexRequest(adLoader.loadScript.firstCall.args[0]); + var optionalResponseParam = [ + [ + { ext: { deal: 'deal1', dealid: 'ixDealID1', dealname: 'deal name 1' } } // first slot first size + // No deal on first slot second size + ] + ]; + var asResponse = IndexUtils.getBidResponse(configuredBids, requestJSON, undefined, undefined, undefined, optionalResponseParam); + cygnus_index_parse_res(asResponse); + var expectedAdapterResponse = IndexUtils.getExpectedAdaptorResponse(configuredBids, asResponse); + + var adapterResponse = {}; + + for (var i = 0; i < bidManager.addBidResponse.callCount; i++) { + var adUnitCode = bidManager.addBidResponse.getCall(i).args[0]; + var bid = bidManager.addBidResponse.getCall(i).args[1]; + + if (typeof adapterResponse[adUnitCode] === 'undefined') { + adapterResponse[adUnitCode] = []; + }; + adapterResponse[adUnitCode].push(bid); + } + + var prebidResponsePair = IndexUtils.matchOnPlacementCode(expectedAdapterResponse, adapterResponse); + + for (var i = 0; i < prebidResponsePair.matched.length; i++) { + var pair = prebidResponsePair.matched[i]; + + for (var j = 0; j < pair.expected.length; j++) { + assert.equal(pair.prebid[j].siteID, pair.expected[j].siteID, 'adapter response for ' + pair.placementCode + ' siteID is set to ' + pair.expected[i].siteID); + assert.equal(pair.prebid[j].bidderCode, pair.expected[j].bidderCode, 'adapter response for ' + pair.placementCode + ' bidderCode is set to ' + pair.expected[i].bidderCode); + assert.equal(pair.prebid[j].width, pair.expected[j].width, 'adapter response for ' + pair.placementCode + ' width is set to ' + pair.expected[i].width); + assert.equal(pair.prebid[j].height, pair.expected[j].height, 'adapter response for ' + pair.placementCode + ' height is set to ' + pair.expected[i].height); + assert.equal(pair.prebid[j].ad, pair.expected[j].ad, 'adapter response for ' + pair.placementCode + ' ad is set to ' + pair.expected[i].ad); + assert.equal(pair.prebid[j].cpm, pair.expected[j].cpm, 'adapter response for ' + pair.placementCode + ' cpm is set to ' + pair.expected[i].cpm); + if (i === 0) { + assert.equal(pair.prebid[j].dealId, pair.expected[j].dealId, 'adapter response for ' + pair.placementCode + ' deaiid is set to ' + pair.expected[i].dealId); + } else { + assert.isUndefined(pair.prebid[j].dealId, 'adapter response for ' + pair.placementCode + ' deaiid is not set'); + } + } + } + + assert.equal(prebidResponsePair.unmatched.expected.length, 0, 'All AS bid response translated to Adapter response for prebid'); + assert.equal(prebidResponsePair.unmatched.prebid.length, 0, 'All Adapter response for prebid is from AS bid'); + }); + + it('test_prebid_indexAdapter_response_deal_2_3: response for single slot with multi size, all returned as non-deal response -> all bid fetched, no response has dealID', function () { + var sizeCount = 2; + var configuredBids = IndexUtils.createBidSlots(1, sizeCount); + adapter.callBids({ bids: configuredBids }); + + var requestJSON = IndexUtils.parseIndexRequest(adLoader.loadScript.firstCall.args[0]); + var optionalResponseParam = [ + [ + {}, + {} + // No deal on first slot first size + // No deal on first slot second size + ] + ]; + var asResponse = IndexUtils.getBidResponse(configuredBids, requestJSON, undefined, undefined, undefined, optionalResponseParam); + + cygnus_index_parse_res(asResponse); + var expectedAdapterResponse = IndexUtils.getExpectedAdaptorResponse(configuredBids, asResponse); + + var adapterResponse = {}; + + for (var i = 0; i < bidManager.addBidResponse.callCount; i++) { + var adUnitCode = bidManager.addBidResponse.getCall(i).args[0]; + var bid = bidManager.addBidResponse.getCall(i).args[1]; + + if (typeof adapterResponse[adUnitCode] === 'undefined') { + adapterResponse[adUnitCode] = []; + }; + adapterResponse[adUnitCode].push(bid); + } + + var prebidResponsePair = IndexUtils.matchOnPlacementCode(expectedAdapterResponse, adapterResponse); + + for (var i = 0; i < prebidResponsePair.matched.length; i++) { + var pair = prebidResponsePair.matched[i]; + for (var j = 0; j < pair.expected.length; j++) { + assert.equal(pair.prebid[i].siteID, pair.expected[i].siteID, 'adapter response for ' + pair.placementCode + ' siteID is set to ' + pair.expected[i].siteID); + assert.equal(pair.prebid[i].bidderCode, pair.expected[i].bidderCode, 'adapter response for ' + pair.placementCode + ' bidderCode is set to ' + pair.expected[i].bidderCode); + assert.equal(pair.prebid[i].width, pair.expected[i].width, 'adapter response for ' + pair.placementCode + ' width is set to ' + pair.expected[i].width); + assert.equal(pair.prebid[i].height, pair.expected[i].height, 'adapter response for ' + pair.placementCode + ' height is set to ' + pair.expected[i].height); + assert.equal(pair.prebid[i].ad, pair.expected[i].ad, 'adapter response for ' + pair.placementCode + ' ad is set to ' + pair.expected[i].ad); + assert.equal(pair.prebid[i].cpm, pair.expected[i].cpm, 'adapter response for ' + pair.placementCode + ' cpm is set to ' + pair.expected[i].cpm); + assert.isUndefined(pair.prebid[i].dealId, 'adapter response for ' + pair.placementCode + ' deaiid is not set'); + } + } + assert.equal(prebidResponsePair.unmatched.expected.length, 0, 'All AS bid response translated to Adapter response for prebid'); + assert.equal(prebidResponsePair.unmatched.prebid.length, 0, 'All Adapter response for prebid is from AS bid'); + }); + + it('test_prebid_indexAdapter_response_deal_3_1: multi slots, all responses contain deal -> all bid fetched into prebid as deal bid', function () { + var slotCount = 2; + var configuredBids = IndexUtils.createBidSlots(slotCount, 1); + adapter.callBids({ bids: configuredBids }); + + var requestJSON = IndexUtils.parseIndexRequest(adLoader.loadScript.firstCall.args[0]); + var optionalResponseParam = [ + [ + { ext: { dealid: 'ixDeal1' } } // first slot first size + ], + [ + { ext: { dealid: 'ixDeal2' } } // second slot first size + ] + ]; + var asResponse = IndexUtils.getBidResponse(configuredBids, requestJSON, undefined, undefined, undefined, optionalResponseParam); + cygnus_index_parse_res(asResponse); + var expectedAdapterResponse = IndexUtils.getExpectedAdaptorResponse(configuredBids, asResponse); + + var adapterResponse = {}; + + for (var i = 0; i < bidManager.addBidResponse.callCount; i++) { + var adUnitCode = bidManager.addBidResponse.getCall(i).args[0]; + var bid = bidManager.addBidResponse.getCall(i).args[1]; + + if (typeof adapterResponse[adUnitCode] === 'undefined') { + adapterResponse[adUnitCode] = []; + }; + adapterResponse[adUnitCode].push(bid); + } + + var prebidResponsePair = IndexUtils.matchOnPlacementCode(expectedAdapterResponse, adapterResponse); + + for (var i = 0; i < prebidResponsePair.matched.length; i++) { + var pair = prebidResponsePair.matched[i]; + assert.equal(pair.prebid[0].siteID, pair.expected[0].siteID, 'adapter response for ' + pair.placementCode + ' siteID is set to ' + pair.expected[0].siteID); + assert.equal(pair.prebid[0].bidderCode, pair.expected[0].bidderCode, 'adapter response for ' + pair.placementCode + ' bidderCode is set to ' + pair.expected[0].bidderCode); + assert.equal(pair.prebid[0].width, pair.expected[0].width, 'adapter response for ' + pair.placementCode + ' width is set to ' + pair.expected[0].width); + assert.equal(pair.prebid[0].height, pair.expected[0].height, 'adapter response for ' + pair.placementCode + ' height is set to ' + pair.expected[0].height); + assert.equal(pair.prebid[0].ad, pair.expected[0].ad, 'adapter response for ' + pair.placementCode + ' ad is set to ' + pair.expected[0].ad); + assert.equal(pair.prebid[0].cpm, pair.expected[0].cpm, 'adapter response for ' + pair.placementCode + ' cpm is set to ' + pair.expected[0].cpm); + assert.equal(pair.prebid[0].dealId, pair.expected[0].dealId, 'adapter response for ' + pair.placementCode + ' deaiid is set to ' + pair.expected[0].dealId); + } + + assert.equal(prebidResponsePair.unmatched.expected.length, 0, 'All AS bid response translated to Adapter response for prebid'); + assert.equal(prebidResponsePair.unmatched.prebid.length, 0, 'All Adapter response for prebid is from AS bid'); + }); + + it('test_prebid_indexAdapter_response_deal_3_2: multi slots, some responses contain deal -> all bid fetched, only deal response has dealID', function () { + var slotCount = 2; + var configuredBids = IndexUtils.createBidSlots(slotCount, 1); + adapter.callBids({ bids: configuredBids }); + + var requestJSON = IndexUtils.parseIndexRequest(adLoader.loadScript.firstCall.args[0]); + var optionalResponseParam = [ + [ + { ext: { dealid: 'ixDeal1' } } // first slot first size + ], + [ + {} + // no deal on second slot first size + ] + ]; + var asResponse = IndexUtils.getBidResponse(configuredBids, requestJSON, undefined, undefined, undefined, optionalResponseParam); + cygnus_index_parse_res(asResponse); + var expectedAdapterResponse = IndexUtils.getExpectedAdaptorResponse(configuredBids, asResponse); + + var adapterResponse = {}; + + for (var i = 0; i < bidManager.addBidResponse.callCount; i++) { + var adUnitCode = bidManager.addBidResponse.getCall(i).args[0]; + var bid = bidManager.addBidResponse.getCall(i).args[1]; + + if (typeof adapterResponse[adUnitCode] === 'undefined') { + adapterResponse[adUnitCode] = []; + }; + adapterResponse[adUnitCode].push(bid); + } + + var prebidResponsePair = IndexUtils.matchOnPlacementCode(expectedAdapterResponse, adapterResponse); + var count = 0; + for (var i = 0; i < prebidResponsePair.matched.length; i++) { + var pair = prebidResponsePair.matched[i]; + assert.equal(pair.prebid[0].siteID, pair.expected[0].siteID, 'adapter response for ' + pair.placementCode + ' siteID is set to ' + pair.expected[0].siteID); + assert.equal(pair.prebid[0].bidderCode, pair.expected[0].bidderCode, 'adapter response for ' + pair.placementCode + ' bidderCode is set to ' + pair.expected[0].bidderCode); + assert.equal(pair.prebid[0].width, pair.expected[0].width, 'adapter response for ' + pair.placementCode + ' width is set to ' + pair.expected[0].width); + assert.equal(pair.prebid[0].height, pair.expected[0].height, 'adapter response for ' + pair.placementCode + ' height is set to ' + pair.expected[0].height); + assert.equal(pair.prebid[0].ad, pair.expected[0].ad, 'adapter response for ' + pair.placementCode + ' ad is set to ' + pair.expected[0].ad); + assert.equal(pair.prebid[0].cpm, pair.expected[0].cpm, 'adapter response for ' + pair.placementCode + ' cpm is set to ' + pair.expected[0].cpm); + if (count === 0) { // if first slot, check deal parameter + assert.equal(pair.prebid[0].dealId, pair.expected[0].dealId, 'adapter response for ' + pair.placementCode + ' deaiid is set to ' + pair.expected[0].dealId); + } else { + assert.isUndefined(pair.prebid[0].dealId, 'adapter response for ' + pair.placementCode + ' deaiid is not defined'); + } + count++; + } + + assert.equal(prebidResponsePair.unmatched.expected.length, 0, 'All AS bid response translated to Adapter response for prebid'); + assert.equal(prebidResponsePair.unmatched.prebid.length, 0, 'All Adapter response for prebid is from AS bid'); + }); + + it('test_prebid_indexAdapter_response_deal_3_3: multi slots, no responses contain deal -> all bid fetched, no response has dealID ', function () { + var slotCount = 2; + var configuredBids = IndexUtils.createBidSlots(slotCount, 1); + adapter.callBids({ bids: configuredBids }); + + var requestJSON = IndexUtils.parseIndexRequest(adLoader.loadScript.firstCall.args[0]); + var optionalResponseParam = [ + [ + {} + // no deal on first slot first size + ], + [ + {} + // no deal on second slot first size + ] + ]; + var asResponse = IndexUtils.getBidResponse(configuredBids, requestJSON, undefined, undefined, undefined, optionalResponseParam); + cygnus_index_parse_res(asResponse); + var expectedAdapterResponse = IndexUtils.getExpectedAdaptorResponse(configuredBids, asResponse); + + var adapterResponse = {}; + + for (var i = 0; i < bidManager.addBidResponse.callCount; i++) { + var adUnitCode = bidManager.addBidResponse.getCall(i).args[0]; + var bid = bidManager.addBidResponse.getCall(i).args[1]; + + if (typeof adapterResponse[adUnitCode] === 'undefined') { + adapterResponse[adUnitCode] = []; + }; + adapterResponse[adUnitCode].push(bid); + } + + var prebidResponsePair = IndexUtils.matchOnPlacementCode(expectedAdapterResponse, adapterResponse); + + for (var i = 0; i < prebidResponsePair.matched.length; i++) { + var pair = prebidResponsePair.matched[i]; + assert.equal(pair.prebid[0].siteID, pair.expected[0].siteID, 'adapter response for ' + pair.placementCode + ' siteID is set to ' + pair.expected[0].siteID); + assert.equal(pair.prebid[0].bidderCode, pair.expected[0].bidderCode, 'adapter response for ' + pair.placementCode + ' bidderCode is set to ' + pair.expected[0].bidderCode); + assert.equal(pair.prebid[0].width, pair.expected[0].width, 'adapter response for ' + pair.placementCode + ' width is set to ' + pair.expected[0].width); + assert.equal(pair.prebid[0].height, pair.expected[0].height, 'adapter response for ' + pair.placementCode + ' height is set to ' + pair.expected[0].height); + assert.equal(pair.prebid[0].ad, pair.expected[0].ad, 'adapter response for ' + pair.placementCode + ' ad is set to ' + pair.expected[0].ad); + assert.equal(pair.prebid[0].cpm, pair.expected[0].cpm, 'adapter response for ' + pair.placementCode + ' cpm is set to ' + pair.expected[0].cpm); + assert.isUndefined(pair.prebid[0].dealId, 'adapter response for ' + pair.placementCode + ' deaiid is not defined'); + } + + assert.equal(prebidResponsePair.unmatched.expected.length, 0, 'All AS bid response translated to Adapter response for prebid'); + assert.equal(prebidResponsePair.unmatched.prebid.length, 0, 'All Adapter response for prebid is from AS bid'); + }); + + it('test_prebid_indexAdapter_tier: one slot with multiple tier -> all tier bids are fetched into prebid', function() { + var slotConfig = { + tier2SiteID: IndexUtils.DefaultSiteID + 1, + tier3SiteID: IndexUtils.DefaultSiteID + 2, + }; + var configuredBids = [ + IndexUtils.createBidSlot(IndexUtils.DefaultPlacementCodePrefix, 'slot_1', [ IndexUtils.supportedSizes[0] ], slotConfig), + ]; + adapter.callBids({ bids: configuredBids }); + + assert.isTrue(adLoader.loadScript.called, 'loadScript get request'); + assert.include(adLoader.loadScript.firstCall.args[0], HeaderTagRequest, 'request is headertag request'); + + var requestJSON = IndexUtils.parseIndexRequest(adLoader.loadScript.firstCall.args[0]); + assert.isNotNull(requestJSON.r.imp, 'headertag request include impression object'); + + var impressionObj = requestJSON.r.imp; + var expandedBids = configuredBids.map(bid => IndexUtils.expandSizes(bid)) + var sidMatched = IndexUtils.matchBidsOnSID(expandedBids, impressionObj); + + assert.equal(sidMatched.matched.length, 3, 'Three slots are configured and sent to AS'); + // check normal site id + var normalSitePair = sidMatched.matched[0]; + + var expectedSlotID = normalSitePair.configured.params.id + '_1'; + assert.equal(normalSitePair.sent.ext.sid, expectedSlotID, 'request ' + normalSitePair.name + ' site ID is set to ' + expectedSlotID); + assert.isString(normalSitePair.sent.ext.sid, 'type of slot ID is string'); + + var expectedSiteID = normalSitePair.configured.params.siteID; + assert.equal(normalSitePair.sent.ext.siteID, expectedSiteID, 'request ' + normalSitePair.name + ' site ID is set to ' + expectedSiteID); + assert.isNumber(normalSitePair.sent.ext.siteID, 'site ID is integer'); + + // check tier 1 site id + var tier2SitePair = sidMatched.matched[1]; + var expectedTierSlotID = 'T1_' + tier2SitePair.configured.params.id + '_1'; + assert.equal(tier2SitePair.sent.ext.sid, expectedTierSlotID, 'request ' + tier2SitePair.name + ' site ID is set to ' + expectedTierSlotID); + assert.isString(tier2SitePair.sent.ext.sid, 'type of slot ID is string'); + + var expectedTierSiteID = tier2SitePair.configured.params.tier2SiteID; + assert.equal(tier2SitePair.sent.ext.siteID, expectedTierSiteID, 'request ' + normalSitePair.name + ' site ID is set to ' + expectedTierSiteID); + assert.isNumber(tier2SitePair.sent.ext.siteID, 'site ID is integer'); + + // check tier 2 site id + var tier3SitePair = sidMatched.matched[2]; + var expectedTierSlotID = 'T2_' + tier3SitePair.configured.params.id + '_1'; + assert.equal(tier3SitePair.sent.ext.sid, expectedTierSlotID, 'request ' + tier3SitePair.name + ' site ID is set to ' + expectedTierSlotID); + assert.isString(tier3SitePair.sent.ext.sid, 'type of slot ID is string'); + + var expectedTier3SiteID = tier3SitePair.configured.params.tier3SiteID; + assert.equal(tier3SitePair.sent.ext.siteID, expectedTier3SiteID, 'request ' + normalSitePair.name + ' site ID is set to ' + expectedTier3SiteID); + assert.isNumber(tier3SitePair.sent.ext.siteID, 'site ID is integer'); + + // check unsent bids + assert.equal(sidMatched.unmatched.configured.length, 0, 'All configured bids are in impression Obj'); + assert.equal(sidMatched.unmatched.sent.length, 0, 'All bids in impression object are from configured bids'); + }); + + it('test_prebid_indexAdapter_callback_bids: callback function defined with bids -> calls callback function with bids', function () { + var callbackCalled = false; + var callback_requestID; + var callback_slots; + window.cygnus_index_args['callback'] = function(requestID, slots) { + callbackCalled = true; + callback_requestID = requestID; + callback_slots = slots; + } + + var configuredBids = IndexUtils.createBidSlots(1, 1); + adapter.callBids({ bids: configuredBids }); + + var requestJSON = IndexUtils.parseIndexRequest(adLoader.loadScript.firstCall.args[0]); + var asResponse = IndexUtils.getBidResponse(configuredBids, requestJSON); + cygnus_index_parse_res(asResponse); + + assert.equal(callbackCalled, true, 'callback function is called'); + assert.equal(callback_requestID, requestJSON.r.id, 'callback requestID matches with actual request ID: ' + requestJSON.r.id); + assert.equal(callback_slots.length, 1, 'callback slots include one slot'); + }); + + it('test_prebid_indexAdapter_callback_nobids: callback function defined with no bids -> calls callback function without bids', function () { + var callbackCalled = false; + var callback_requestID; + var callback_slots; + window.cygnus_index_args['callback'] = function(requestID, slots) { + callbackCalled = true; + callback_requestID = requestID; + callback_slots = slots; + } + + var configuredBids = IndexUtils.createBidSlots(1, 1); + adapter.callBids({ bids: configuredBids }); + + var requestJSON = IndexUtils.parseIndexRequest(adLoader.loadScript.firstCall.args[0]); + var asResponse = IndexUtils.getBidResponse(configuredBids, requestJSON, undefined, undefined, [[true]]); // pass on bid + cygnus_index_parse_res(asResponse); + + assert.equal(callbackCalled, true, 'callback function is called'); + assert.equal(callback_requestID, requestJSON.r.id, 'callback requestID matches with actual request ID: ' + requestJSON.r.id); + assert.isUndefined(callback_slots, 'callback slot is undefined because all bids passed on bid'); + }); + + it('test_prebid_indexAdapter_response_sizeID_1: multiple prebid size slot, index slots with size for all prebid slots -> all size in AS request, no size ID', function () { + var slotID_1 = '52'; + var slotID_2 = '53'; + var slotSizes_1 = IndexUtils.supportedSizes[0]; + var slotSizes_2 = IndexUtils.supportedSizes[1]; + + var configuredBids = [ + IndexUtils.createBidSlot(IndexUtils.DefaultPlacementCodePrefix + slotID_1, slotID_1, [ slotSizes_1, slotSizes_2 ], { slotSize: slotSizes_1 }), + IndexUtils.createBidSlot(IndexUtils.DefaultPlacementCodePrefix + slotID_2, slotID_2, [ slotSizes_1, slotSizes_2 ], { siteID: IndexUtils.DefaultSiteID + 1 }) + ]; + + adapter.callBids({ bids: configuredBids }); + + var requestJSON = IndexUtils.parseIndexRequest(adLoader.loadScript.firstCall.args[0]); + var asResponse = IndexUtils.getBidResponse(configuredBids, requestJSON, undefined, undefined, [[true]]); // pass on bid + cygnus_index_parse_res(asResponse); + + var adapterResponse = {}; + + for (var i = 0; i < bidManager.addBidResponse.callCount; i++) { + var adUnitCode = bidManager.addBidResponse.getCall(i).args[0]; + var bid = bidManager.addBidResponse.getCall(i).args[1]; + + if (typeof adapterResponse[adUnitCode] === 'undefined') { + adapterResponse[adUnitCode] = []; + }; + adapterResponse[adUnitCode].push(bid); + } + }); +}); diff --git a/test/spec/modules/indexExchangeBidAdapter_validadtion_spec.js b/test/spec/modules/indexExchangeBidAdapter_validadtion_spec.js new file mode 100644 index 00000000000..004a808e6c4 --- /dev/null +++ b/test/spec/modules/indexExchangeBidAdapter_validadtion_spec.js @@ -0,0 +1,1496 @@ +import Adapter from '../../../modules/indexExchangeBidAdapter'; +import adLoader from '../../../src/adloader'; + +var assert = require('chai').assert; +var IndexUtils = require('../../helpers/index_adapter_utils.js'); +var HeaderTagRequest = '/cygnus'; +var ADAPTER_CODE = 'indexExchange'; + +describe('indexExchange adapter - Validation', function () { + let adapter; + let sandbox; + + beforeEach(function() { + window._IndexRequestData = {}; + _IndexRequestData.impIDToSlotID = {}; + _IndexRequestData.reqOptions = {}; + _IndexRequestData.targetIDToResp = {}; + window.cygnus_index_args = {}; + + adapter = new Adapter(); + sandbox = sinon.sandbox.create(); + sandbox.stub(adLoader, 'loadScript'); + }); + + afterEach(function() { + sandbox.restore(); + }); + + it('test_prebid_indexAdapter_sizeValidation_1: request slot has supported and unsupported size -> unsupported size ignored in IX demand request', function () { + // create 2 sizes for 1 slot, 1 for supported size, the other is not supported + var unsupportedSize = IndexUtils.unsupportedSizes[0]; + var configuredBids = [ + IndexUtils.createBidSlot(IndexUtils.DefaultPlacementCodePrefix, 'slot_1', [ IndexUtils.supportedSizes[0], unsupportedSize ]) + ]; + + adapter.callBids({ bids: configuredBids }); + + assert.isTrue(adLoader.loadScript.called, 'loadScript get request'); + assert.include(adLoader.loadScript.firstCall.args[0], HeaderTagRequest, 'request is headertag request'); + + var requestJSON = IndexUtils.parseIndexRequest(adLoader.loadScript.firstCall.args[0]); + assert.isNotNull(requestJSON.r.imp, 'headertag request include impression object'); + + var impressionObj = requestJSON.r.imp; + + var expandedBids = configuredBids.map(bid => IndexUtils.expandSizes(bid)) + var sidMatched = IndexUtils.matchBidsOnSID(expandedBids, impressionObj); + for (var i = 0; i < sidMatched.matched.length; i++) { + var pair = sidMatched.matched[i]; + + assert.equal(pair.sent.banner.w, pair.configured.size[0], 'request ' + pair.name + ' width is set to ' + pair.configured.size[0]); + assert.equal(pair.sent.banner.h, pair.configured.size[1], 'request ' + pair.name + ' width is set to ' + pair.configured.size[1]); + assert.equal(pair.sent.ext.siteID, pair.configured.params.siteID, 'request ' + pair.name + ' siteID is set to ' + pair.configured.params.siteID); + } + + assert.equal(sidMatched.unmatched.sent.length, 0, 'All bids in impression object are from configured bids'); + + assert.equal(sidMatched.unmatched.configured.length, 1, '1 configured bid is not in impression Obj'); + assert.equal(sidMatched.unmatched.configured[0].size, unsupportedSize, 'configured bid not in impression obj size width is' + JSON.stringify(unsupportedSize)); + }); + + it('test_prebid_indexAdapter_sizeValidation_2_1: some slot has unsupported size -> unsupported slot ignored in IX demand request', function () { + // create 2 slot, 1 for supported size, the other is not supported + var unsupportedSize = IndexUtils.unsupportedSizes[0]; + var configuredBids = [ + IndexUtils.createBidSlot(IndexUtils.DefaultPlacementCodePrefix + 'supported', 'slot_1', [ IndexUtils.supportedSizes[0], ], { siteID: IndexUtils.DefaultSiteID }), + IndexUtils.createBidSlot(IndexUtils.DefaultPlacementCodePrefix + 'unspported', 'slot_2', [ unsupportedSize ], { siteID: IndexUtils.DefaultSiteID + 1}) + ]; + + adapter.callBids({ bids: configuredBids }); + + assert.isTrue(adLoader.loadScript.called, 'loadScript get request'); + assert.include(adLoader.loadScript.firstCall.args[0], HeaderTagRequest, 'request is headertag request'); + + var requestJSON = IndexUtils.parseIndexRequest(adLoader.loadScript.firstCall.args[0]); + assert.isNotNull(requestJSON.r.imp, 'headertag request include impression object'); + + var impressionObj = requestJSON.r.imp; + + var expandedBids = configuredBids.map(bid => IndexUtils.expandSizes(bid)) + var sidMatched = IndexUtils.matchBidsOnSID(expandedBids, impressionObj); + for (var i = 0; i < sidMatched.matched.length; i++) { + var pair = sidMatched.matched[i]; + + assert.equal(pair.sent.banner.w, pair.configured.size[0], 'request ' + pair.name + ' width is set to ' + pair.configured.size[0]); + assert.equal(pair.sent.banner.h, pair.configured.size[1], 'request ' + pair.name + ' width is set to ' + pair.configured.size[1]); + assert.equal(pair.sent.ext.siteID, pair.configured.params.siteID, 'request ' + pair.name + ' siteID is set to ' + pair.configured.params.siteID); + } + + assert.equal(sidMatched.unmatched.sent.length, 0, 'All bids in impression object are from configured bids'); + + assert.equal(sidMatched.unmatched.configured.length, 1, '1 configured bid is not in impression Obj'); + assert.equal(sidMatched.unmatched.configured[0].size, unsupportedSize, 'configured bid not in impression obj size width is' + JSON.stringify(unsupportedSize)); + assert.equal(sidMatched.unmatched.configured[0].params.id, 'slot_2', 'configured bid not in impression obj id is slot_2'); + assert.equal(sidMatched.unmatched.configured[0].params.siteID, IndexUtils.DefaultSiteID + 1, 'configured bid not in impression obj siteID is ' + (IndexUtils.DefaultSiteID + 1)); + }); + + it('test_prebid_indexAdapter_sizeValidation_2_2: multiple slots with sinle size, all slot has supported size -> all slots are sent to IX demand', function () { + // create 2 slot, 1 for supported size, the other is not supported + var unsupportedSize = IndexUtils.unsupportedSizes[0]; + var configuredBids = [ + IndexUtils.createBidSlot(IndexUtils.DefaultPlacementCodePrefix + 'supported1', 'slot_1', [ IndexUtils.supportedSizes[0] ], { siteID: IndexUtils.DefaultSiteID }), + IndexUtils.createBidSlot(IndexUtils.DefaultPlacementCodePrefix + 'supported2', 'slot_2', [ IndexUtils.supportedSizes[1] ], { siteID: IndexUtils.DefaultSiteID + 1}) + ]; + + adapter.callBids({ bids: configuredBids }); + + assert.isTrue(adLoader.loadScript.called, 'loadScript get request'); + assert.include(adLoader.loadScript.firstCall.args[0], HeaderTagRequest, 'request is headertag request'); + + var requestJSON = IndexUtils.parseIndexRequest(adLoader.loadScript.firstCall.args[0]); + assert.isNotNull(requestJSON.r.imp, 'headertag request include impression object'); + + var impressionObj = requestJSON.r.imp; + + var expandedBids = configuredBids.map(bid => IndexUtils.expandSizes(bid)) + var sidMatched = IndexUtils.matchBidsOnSID(expandedBids, impressionObj); + for (var i = 0; i < sidMatched.matched.length; i++) { + var pair = sidMatched.matched[i]; + + assert.equal(pair.sent.banner.w, pair.configured.size[0], 'request ' + pair.name + ' width is set to ' + pair.configured.size[0]); + assert.equal(pair.sent.banner.h, pair.configured.size[1], 'request ' + pair.name + ' width is set to ' + pair.configured.size[1]); + assert.equal(pair.sent.ext.siteID, pair.configured.params.siteID, 'request ' + pair.name + ' siteID is set to ' + pair.configured.params.siteID); + } + + assert.equal(sidMatched.unmatched.sent.length, 0, 'All bids in impression object are from configured bids'); + assert.equal(sidMatched.unmatched.configured.length, 0, '0 configured bid is not in impression Obj'); + }); + + it('test_prebid_indexAdapter_sizeValidation_2_3: multiple slots with sinle size, all slot has unsupported size -> all slots are ignored', function () { + // create 2 slot, 1 for supported size, the other is not supported + var unsupportedSize = IndexUtils.unsupportedSizes[0]; + var configuredBids = [ + IndexUtils.createBidSlot(IndexUtils.DefaultPlacementCodePrefix + 'unsupported1', 'slot_1', [ IndexUtils.unsupportedSizes[0] ], { siteID: IndexUtils.DefaultSiteID }), + IndexUtils.createBidSlot(IndexUtils.DefaultPlacementCodePrefix + 'unsupported2', 'slot_2', [ IndexUtils.unsupportedSizes[1] ], { siteID: IndexUtils.DefaultSiteID + 1}) + ]; + adapter.callBids({ bids: configuredBids }); + + assert.isUndefined(adLoader.loadScript.firstCall.args[0], 'no request made to IX demand'); + }); + + it('test_prebid_indexAdapter_sizeValidation_3_1: one slot has supported, unsupported, supported size -> unsupported slot ignored in IX demand request', function () { + // create 2 slot, 1 for supported size, the other is not supported + var unsupportedSize = IndexUtils.unsupportedSizes[0]; + var configuredBids = [ + IndexUtils.createBidSlot(IndexUtils.DefaultPlacementCodePrefix + 'somesupported', 'slot_1', [ IndexUtils.supportedSizes[0], unsupportedSize, IndexUtils.supportedSizes[1] ], { siteID: IndexUtils.DefaultSiteID }), + IndexUtils.createBidSlot(IndexUtils.DefaultPlacementCodePrefix + 'allsupported', 'slot_2', [ IndexUtils.supportedSizes[2], IndexUtils.supportedSizes[3] ], { siteID: IndexUtils.DefaultSiteID + 1}) + ]; + + adapter.callBids({ bids: configuredBids }); + + assert.isTrue(adLoader.loadScript.called, 'loadScript get request'); + assert.include(adLoader.loadScript.firstCall.args[0], HeaderTagRequest, 'request is headertag request'); + + var requestJSON = IndexUtils.parseIndexRequest(adLoader.loadScript.firstCall.args[0]); + assert.isNotNull(requestJSON.r.imp, 'headertag request include impression object'); + + var impressionObj = requestJSON.r.imp; + + var expandedBids = configuredBids.map(bid => IndexUtils.expandSizes(bid)) + var sidMatched = IndexUtils.matchBidsOnSize(expandedBids, impressionObj); + for (var i = 0; i < sidMatched.matched.length; i++) { + var pair = sidMatched.matched[i]; + + assert.equal(pair.sent.banner.w, pair.configured.size[0], 'request ' + pair.name + ' width is set to ' + pair.configured.size[0]); + assert.equal(pair.sent.banner.h, pair.configured.size[1], 'request ' + pair.name + ' width is set to ' + pair.configured.size[1]); + assert.equal(pair.sent.ext.siteID, pair.configured.params.siteID, 'request ' + pair.name + ' siteID is set to ' + pair.configured.params.siteID); + } + + assert.equal(sidMatched.unmatched.sent.length, 0, 'All bids in impression object are from configured bids'); + + assert.equal(sidMatched.unmatched.configured.length, 1, '1 configured bid is not in impression Obj'); + assert.equal(sidMatched.unmatched.configured[0].size, unsupportedSize, 'configured bid not in impression obj size width is' + JSON.stringify(unsupportedSize)); + assert.equal(sidMatched.unmatched.configured[0].params.id, 'slot_1', 'configured bid not in impression obj id is slot_1'); + assert.equal(sidMatched.unmatched.configured[0].params.siteID, IndexUtils.DefaultSiteID, 'configured bid not in impression obj siteID is ' + (IndexUtils.DefaultSiteID)); + }); + + it('test_prebid_indexAdapter_sizeValidation_3_2: one slot has unsupported, supported, unsupported size -> unsupported slot ignored in IX demand request', function () { + // create 2 slot, 1 for supported size, the other is not supported + var unsupportedSize1 = IndexUtils.unsupportedSizes[0]; + var unsupportedSize2 = IndexUtils.unsupportedSizes[1]; + var configuredBids = [ + IndexUtils.createBidSlot(IndexUtils.DefaultPlacementCodePrefix + 'somesupported', 'slot_1', [ unsupportedSize1, IndexUtils.supportedSizes[1], unsupportedSize2 ], { siteID: IndexUtils.DefaultSiteID }), + IndexUtils.createBidSlot(IndexUtils.DefaultPlacementCodePrefix + 'allsupported', 'slot_2', [ IndexUtils.supportedSizes[2], IndexUtils.supportedSizes[3] ], { siteID: IndexUtils.DefaultSiteID + 1}) + ]; + + adapter.callBids({ bids: configuredBids }); + + assert.isTrue(adLoader.loadScript.called, 'loadScript get request'); + assert.include(adLoader.loadScript.firstCall.args[0], HeaderTagRequest, 'request is headertag request'); + + var requestJSON = IndexUtils.parseIndexRequest(adLoader.loadScript.firstCall.args[0]); + assert.isNotNull(requestJSON.r.imp, 'headertag request include impression object'); + + var impressionObj = requestJSON.r.imp; + + var expandedBids = configuredBids.map(bid => IndexUtils.expandSizes(bid)) + var sidMatched = IndexUtils.matchBidsOnSize(expandedBids, impressionObj); + for (var i = 0; i < sidMatched.matched.length; i++) { + var pair = sidMatched.matched[i]; + + assert.equal(pair.sent.banner.w, pair.configured.size[0], 'request ' + pair.name + ' width is set to ' + pair.configured.size[0]); + assert.equal(pair.sent.banner.h, pair.configured.size[1], 'request ' + pair.name + ' width is set to ' + pair.configured.size[1]); + assert.equal(pair.sent.ext.siteID, pair.configured.params.siteID, 'request ' + pair.name + ' siteID is set to ' + pair.configured.params.siteID); + } + + assert.equal(sidMatched.unmatched.sent.length, 0, 'All bids in impression object are from configured bids'); + + assert.equal(sidMatched.unmatched.configured.length, 2, '2 configured bid is not in impression Obj'); + + assert.equal(sidMatched.unmatched.configured[0].size, unsupportedSize1, 'configured bid not in impression obj size width is' + JSON.stringify(unsupportedSize1)); + assert.equal(sidMatched.unmatched.configured[0].params.id, 'slot_1', 'configured bid not in impression obj id is slot_1'); + assert.equal(sidMatched.unmatched.configured[0].params.siteID, IndexUtils.DefaultSiteID, 'configured bid not in impression obj siteID is ' + (IndexUtils.DefaultSiteID)); + + assert.equal(sidMatched.unmatched.configured[1].size, unsupportedSize2, 'configured bid not in impression obj size width is' + JSON.stringify(unsupportedSize2)); + assert.equal(sidMatched.unmatched.configured[1].params.id, 'slot_1', 'configured bid not in impression obj id is slot_1'); + assert.equal(sidMatched.unmatched.configured[1].params.siteID, IndexUtils.DefaultSiteID, 'configured bid not in impression obj siteID is ' + (IndexUtils.DefaultSiteID)); + }); + + it('test_prebid_indexAdapter_sizeValidation_3_3: multiple slots, all slots have supported size -> all slots are included in IX demand request', function () { + var configuredBids = [ + IndexUtils.createBidSlot(IndexUtils.DefaultPlacementCodePrefix + 'allsupported1', 'slot_1', [ IndexUtils.supportedSizes[0], IndexUtils.supportedSizes[1] ], { siteID: IndexUtils.DefaultSiteID }), + IndexUtils.createBidSlot(IndexUtils.DefaultPlacementCodePrefix + 'allsupported2', 'slot_2', [ IndexUtils.supportedSizes[2], IndexUtils.supportedSizes[3] ], { siteID: IndexUtils.DefaultSiteID + 1}) + ]; + + adapter.callBids({ bids: configuredBids }); + + assert.isTrue(adLoader.loadScript.called, 'loadScript get request'); + assert.include(adLoader.loadScript.firstCall.args[0], HeaderTagRequest, 'request is headertag request'); + + var requestJSON = IndexUtils.parseIndexRequest(adLoader.loadScript.firstCall.args[0]); + assert.isNotNull(requestJSON.r.imp, 'headertag request include impression object'); + + var impressionObj = requestJSON.r.imp; + + var expandedBids = configuredBids.map(bid => IndexUtils.expandSizes(bid)) + var sidMatched = IndexUtils.matchBidsOnSize(expandedBids, impressionObj); + for (var i = 0; i < sidMatched.matched.length; i++) { + var pair = sidMatched.matched[i]; + + assert.equal(pair.sent.banner.w, pair.configured.size[0], 'request ' + pair.name + ' width is set to ' + pair.configured.size[0]); + assert.equal(pair.sent.banner.h, pair.configured.size[1], 'request ' + pair.name + ' width is set to ' + pair.configured.size[1]); + assert.equal(pair.sent.ext.siteID, pair.configured.params.siteID, 'request ' + pair.name + ' siteID is set to ' + pair.configured.params.siteID); + } + + assert.equal(sidMatched.unmatched.sent.length, 0, 'All bids in impression object are from configured bids'); + + assert.equal(sidMatched.unmatched.configured.length, 0, '0 configured bid is not in impression Obj'); + }); + + it('test_prebid_indexAdapter_sizeValidation_3_4: multiple slots, all slots have unsupported size -> no slots are sent to IX demand', function () { + var configuredBids = [ + IndexUtils.createBidSlot(IndexUtils.DefaultPlacementCodePrefix + 'allsupported1', 'slot_1', [ IndexUtils.unsupportedSizes[0], IndexUtils.unsupportedSizes[1] ], { siteID: IndexUtils.DefaultSiteID }), + IndexUtils.createBidSlot(IndexUtils.DefaultPlacementCodePrefix + 'allsupported2', 'slot_2', [ IndexUtils.unsupportedSizes[2], IndexUtils.unsupportedSizes[3] ], { siteID: IndexUtils.DefaultSiteID + 1}) + ]; + adapter.callBids({ bids: configuredBids }); + + assert.isUndefined(adLoader.loadScript.firstCall.args[0], 'No request to IX demand'); + }); + + it('test_prebid_indexAdapter_param_timeout_integer: timeout is integer -> t parameter that matches with the integer', function () { + var testTimeout = 100; // integer timeout + var configuredBids = [ + IndexUtils.createBidSlot(IndexUtils.DefaultPlacementCodePrefix, 'slot_1', [ IndexUtils.supportedSizes[0] ], { timeout: testTimeout }), + ]; + adapter.callBids({ bids: configuredBids }); + + assert.isTrue(adLoader.loadScript.called, 'loadScript get request'); + assert.include(adLoader.loadScript.firstCall.args[0], HeaderTagRequest, 'request is headertag request'); + + var requestJSON = IndexUtils.parseIndexRequest(adLoader.loadScript.firstCall.args[0]); + assert.equal(requestJSON.t, testTimeout, 't parameter matches timeout and is included in AS request parameter'); + }); + + it('test_prebid_indexAdapter_param_timeout_quoted_integer: timeout is quoted integer -> t parameter that matches with the integer', function () { + var testTimeout = '100'; // quoted integer timeout + var configuredBids = [ + IndexUtils.createBidSlot(IndexUtils.DefaultPlacementCodePrefix, 'slot_1', [ IndexUtils.supportedSizes[0] ], { timeout: testTimeout }), + ]; + adapter.callBids({ bids: configuredBids }); + + assert.isTrue(adLoader.loadScript.called, 'loadScript get request'); + assert.include(adLoader.loadScript.firstCall.args[0], HeaderTagRequest, 'request is headertag request'); + + var requestJSON = IndexUtils.parseIndexRequest(adLoader.loadScript.firstCall.args[0]); + assert.equal(requestJSON.t, testTimeout, 't parameter matches timeout and is included in AS request parameter'); + }); + + it('test_prebid_indexAdapter_param_timeout_float: timeout is float number -> t parameter is not included in AS request', function () { + var testTimeout = 1.234; + var configuredBids = [ + IndexUtils.createBidSlot(IndexUtils.DefaultPlacementCodePrefix, 'slot_1', [ IndexUtils.supportedSizes[0] ], { timeout: testTimeout }), + ]; + adapter.callBids({ bids: configuredBids }); + + assert.isTrue(adLoader.loadScript.called, 'loadScript get request'); + assert.include(adLoader.loadScript.firstCall.args[0], HeaderTagRequest, 'request is headertag request'); + + var requestJSON = IndexUtils.parseIndexRequest(adLoader.loadScript.firstCall.args[0]); + assert.isUndefined(requestJSON.t, 't parameter is not included in AS request parameter'); + }); + + it('test_prebid_indexAdapter_param_timeout_float: timeout is float number -> t parameter is not included in AS request', function () { + var testTimeout = 1.234; + var configuredBids = [ + IndexUtils.createBidSlot(IndexUtils.DefaultPlacementCodePrefix, 'slot_1', [ IndexUtils.supportedSizes[0] ], { timeout: testTimeout }), + ]; + adapter.callBids({ bids: configuredBids }); + + assert.isTrue(adLoader.loadScript.called, 'loadScript get request'); + assert.include(adLoader.loadScript.firstCall.args[0], HeaderTagRequest, 'request is headertag request'); + + var requestJSON = IndexUtils.parseIndexRequest(adLoader.loadScript.firstCall.args[0]); + assert.isUndefined(requestJSON.t, 't parameter is not included in AS request parameter'); + }); + + it('test_prebid_indexAdapter_param_timeout_string: timeout is string -> t parameter is not included in AS request', function () { + var testTimeout = 'string'; + var configuredBids = [ + IndexUtils.createBidSlot(IndexUtils.DefaultPlacementCodePrefix, 'slot_1', [ IndexUtils.supportedSizes[0] ], { timeout: testTimeout }), + ]; + adapter.callBids({ bids: configuredBids }); + + assert.isTrue(adLoader.loadScript.called, 'loadScript get request'); + assert.include(adLoader.loadScript.firstCall.args[0], HeaderTagRequest, 'request is headertag request'); + + var requestJSON = IndexUtils.parseIndexRequest(adLoader.loadScript.firstCall.args[0]); + assert.isUndefined(requestJSON.t, 't parameter is not included in AS request parameter'); + }); + + it('test_prebid_indexAdapter_param_timeout_array: timeout is array -> t parameter is not included in AS request', function () { + var testTimeout = [ 'abc' ]; + var configuredBids = [ + IndexUtils.createBidSlot(IndexUtils.DefaultPlacementCodePrefix, 'slot_1', [ IndexUtils.supportedSizes[0] ], { timeout: testTimeout }), + ]; + adapter.callBids({ bids: configuredBids }); + + assert.isTrue(adLoader.loadScript.called, 'loadScript get request'); + assert.include(adLoader.loadScript.firstCall.args[0], HeaderTagRequest, 'request is headertag request'); + + var requestJSON = IndexUtils.parseIndexRequest(adLoader.loadScript.firstCall.args[0]); + assert.isUndefined(requestJSON.t, 't parameter is not included in AS request parameter'); + }); + + it('test_prebid_indexAdapter_param_timeout_hash: timeout is hash -> t parameter is not included in AS request', function () { + var testTimeout = { 'timeout': 100 }; + var configuredBids = [ + IndexUtils.createBidSlot(IndexUtils.DefaultPlacementCodePrefix, 'slot_1', [ IndexUtils.supportedSizes[0] ], { timeout: testTimeout }), + ]; + adapter.callBids({ bids: configuredBids }); + + assert.isTrue(adLoader.loadScript.called, 'loadScript get request'); + assert.include(adLoader.loadScript.firstCall.args[0], HeaderTagRequest, 'request is headertag request'); + + var requestJSON = IndexUtils.parseIndexRequest(adLoader.loadScript.firstCall.args[0]); + assert.isUndefined(requestJSON.t, 't parameter is not included in AS request parameter'); + }); + + it('test_prebid_indexAdapter_param_timeout_zero: timeout is zero -> t parameter is not included in AS request', function () { + var testTimeout = 0; + var configuredBids = [ + IndexUtils.createBidSlot(IndexUtils.DefaultPlacementCodePrefix, 'slot_1', [ IndexUtils.supportedSizes[0] ], { timeout: testTimeout }), + ]; + adapter.callBids({ bids: configuredBids }); + + assert.isTrue(adLoader.loadScript.called, 'loadScript get request'); + assert.include(adLoader.loadScript.firstCall.args[0], HeaderTagRequest, 'request is headertag request'); + + var requestJSON = IndexUtils.parseIndexRequest(adLoader.loadScript.firstCall.args[0]); + assert.isUndefined(requestJSON.t, 't parameter is not included in AS request parameter'); + }); + + it('test_prebid_indexAdapter_param_timeout_negative: timeout is negative integer -> t parameter is not included in AS request', function () { + var testTimeout = -100; + var configuredBids = [ + IndexUtils.createBidSlot(IndexUtils.DefaultPlacementCodePrefix, 'slot_1', [ IndexUtils.supportedSizes[0] ], { timeout: testTimeout }), + ]; + adapter.callBids({ bids: configuredBids }); + + assert.isTrue(adLoader.loadScript.called, 'loadScript get request'); + assert.include(adLoader.loadScript.firstCall.args[0], HeaderTagRequest, 'request is headertag request'); + + var requestJSON = IndexUtils.parseIndexRequest(adLoader.loadScript.firstCall.args[0]); + assert.isUndefined(requestJSON.t, 't parameter is not included in AS request parameter'); + }); + + it('test_prebid_indexAdapter_param_timeout_too_big: timeout is bigger than AS max timeout -> t parameter is not included in AS request', function () { + var testTimeout = 25000; // very large timeout + var configuredBids = [ + IndexUtils.createBidSlot(IndexUtils.DefaultPlacementCodePrefix, 'slot_1', [ IndexUtils.supportedSizes[0] ], { timeout: testTimeout }), + ]; + adapter.callBids({ bids: configuredBids }); + + assert.isTrue(adLoader.loadScript.called, 'loadScript get request'); + assert.include(adLoader.loadScript.firstCall.args[0], HeaderTagRequest, 'request is headertag request'); + + var requestJSON = IndexUtils.parseIndexRequest(adLoader.loadScript.firstCall.args[0]); + assert.equal(requestJSON.t, testTimeout, 't parameter matches timeout and is included in AS request parameter'); + }); + + it('test_prebid_indexAdapter_param_timeout_missing: timeout is missing -> t parameter is not included in AS request', function () { + var configuredBids = [ + IndexUtils.createBidSlot(IndexUtils.DefaultPlacementCodePrefix, 'slot_1', [ IndexUtils.supportedSizes[0] ]), + ]; + adapter.callBids({ bids: configuredBids }); + + assert.isTrue(adLoader.loadScript.called, 'loadScript get request'); + assert.include(adLoader.loadScript.firstCall.args[0], HeaderTagRequest, 'request is headertag request'); + + var requestJSON = IndexUtils.parseIndexRequest(adLoader.loadScript.firstCall.args[0]); + assert.isUndefined(requestJSON.t, 't parameter is not included in AS request parameter'); + }); + + it('test_prebid_indexAdapter_param_timeout_empty_string: timeout is empty string -> t parameter is not included in AS request', function () { + var testTimeout = ''; + var configuredBids = [ + IndexUtils.createBidSlot(IndexUtils.DefaultPlacementCodePrefix, 'slot_1', [ IndexUtils.supportedSizes[0] ], { timeout: testTimeout}), + ]; + adapter.callBids({ bids: configuredBids }); + + assert.isTrue(adLoader.loadScript.called, 'loadScript get request'); + assert.include(adLoader.loadScript.firstCall.args[0], HeaderTagRequest, 'request is headertag request'); + + var requestJSON = IndexUtils.parseIndexRequest(adLoader.loadScript.firstCall.args[0]); + assert.isUndefined(requestJSON.t, 't parameter is not included in AS request parameter'); + }); + + var test_indexAdapter_slotid = [ + { + 'testname': 'test_prebid_indexAdapter_slotid_integer: slot ID is integer -> slot ID sent to AS in string', + 'slotID': 123, + 'expected': 'pass' + }, + { + 'testname': 'test_prebid_indexAdapter_slotid_quoted_integer: slot ID is quoted_integer -> slot ID sent to AS in string', + 'slotID': '123', + 'expected': 'pass' + }, + { + 'testname': 'test_prebid_indexAdapter_slotid_float: slot ID is float -> slot ID sent to AS in string', + 'slotID': 123.45, + 'expected': 'pass' + }, + { + 'testname': 'test_prebid_indexAdapter_slotid_string: slot ID is string -> slot ID sent to AS in string', + 'slotID': 'string', + 'expected': 'pass' + }, + { + 'testname': 'test_prebid_indexAdapter_slotid_array: slot ID is array -> slot is not sent to AS', + 'slotID': [ 'arrayelement1', 'arrayelement2' ], + 'expected': 'fail' + }, + { + 'testname': 'test_prebid_indexAdapter_slotid_hash: slot ID is hash -> slot is not sent to AS', + 'slotID': { 'hashName': 'hashKey' }, + 'expected': 'fail' + }, + { + 'testname': 'test_prebid_indexAdapter_slotid_zero: slot ID is zero integer -> slot ID sent to AS in string', + 'slotID': 0, + 'expected': 'pass' + }, + { + 'testname': 'test_prebid_indexAdapter_slotid_negative: slot ID is negative integer -> slot ID sent to AS in string', + 'slotID': -100, + 'expected': 'pass' + }, + { + 'testname': 'test_prebid_indexAdapter_slotid_undefined: slot ID is undefined -> slot is not sent to AS', + 'slotID': undefined, + 'expected': 'fail' + }, + { + 'testname': 'test_prebid_indexAdapter_slotid_missing: slot ID is missing -> slot is not sent to AS', + 'param': { 'missingSlotID': true}, + 'expected': 'invalid' + } + ]; + + function base_prebid_indexAdapter_slotid (testname, slotID, expected, param) { + it(testname, function() { + var configuredBids = [ + IndexUtils.createBidSlot(IndexUtils.DefaultPlacementCodePrefix, slotID, [ IndexUtils.supportedSizes[0] ], param), + ]; + adapter.callBids({ bids: configuredBids }); + if (expected == 'pass') { + assert.isTrue(adLoader.loadScript.called, 'loadScript get request'); + assert.include(adLoader.loadScript.firstCall.args[0], HeaderTagRequest, 'request is headertag request'); + + var requestJSON = IndexUtils.parseIndexRequest(adLoader.loadScript.firstCall.args[0]); + assert.isNotNull(requestJSON.r.imp, 'headertag request include impression object'); + + var impressionObj = requestJSON.r.imp; + + var expandedBids = configuredBids.map(bid => IndexUtils.expandSizes(bid)) + var sidMatched = IndexUtils.matchBidsOnSID(expandedBids, impressionObj); + for (var i = 0; i < sidMatched.matched.length; i++) { + var pair = sidMatched.matched[i]; + + var actualSlotID = pair.sent.ext.sid; + var expectedSlotID = pair.configured.params.id + '_1'; + assert.equal(actualSlotID, expectedSlotID, 'request ' + pair.name + ' slot ID is set to ' + expectedSlotID); + assert.isString(actualSlotID, 'slotID is string'); + } + + assert.equal(sidMatched.unmatched.configured.length, 0, 'All configured bids are in impression Obj'); + assert.equal(sidMatched.unmatched.sent.length, 0, 'All bids in impression object are from configured bids'); + } else if (expected == 'invalid') { + // case where callBids throws out request due to missing params + assert.isFalse(adLoader.loadScript.called, 'No request to AS') + } else { + assert.strictEqual(typeof indexBidRequest, 'undefined', 'No request to AS'); + } + }); + }; + + for (var i = 0; i < test_indexAdapter_slotid.length; i++) { + var test = test_indexAdapter_slotid[i]; + base_prebid_indexAdapter_slotid(test.testname, test.slotID, test.expected, test.param); + } + + it('test_prebid_indexAdapter_slotid_multiple_slot: uniqueness for multiple slots -> all slots in ad server request with unique slot id', function() { + var configuredBids = [ + IndexUtils.createBidSlot(IndexUtils.DefaultPlacementCodePrefix, 'slot_1', [ IndexUtils.supportedSizes[0] ]), + IndexUtils.createBidSlot(IndexUtils.DefaultPlacementCodePrefix, 'slot_2', [ IndexUtils.supportedSizes[1] ]), + ]; + adapter.callBids({ bids: configuredBids }); + assert.isTrue(adLoader.loadScript.called, 'loadScript get request'); + + assert.include(adLoader.loadScript.firstCall.args[0], HeaderTagRequest, 'request is headertag request'); + + var requestJSON = IndexUtils.parseIndexRequest(adLoader.loadScript.firstCall.args[0]); + assert.isNotNull(requestJSON.r.imp, 'headertag request include impression object'); + + var impressionObj = requestJSON.r.imp; + + var expandedBids = configuredBids.map(bid => IndexUtils.expandSizes(bid)) + var sidMatched = IndexUtils.matchBidsOnSID(expandedBids, impressionObj); + for (var i = 0; i < sidMatched.matched.length; i++) { + var pair = sidMatched.matched[i]; + + var actualSlotID = pair.sent.ext.sid; + var expectedSlotID = pair.configured.params.id + '_1'; + assert.equal(actualSlotID, expectedSlotID, 'request ' + pair.name + ' slot ID is set to ' + expectedSlotID); + assert.isString(actualSlotID, 'slotID is string'); + } + + assert.equal(sidMatched.unmatched.configured.length, 0, 'All configured bids are in impression Obj'); + assert.equal(sidMatched.unmatched.sent.length, 0, 'All bids in impression object are from configured bids'); + }); + + it('test_prebid_indexAdapter_slotid_multiple_same: same across some slots -> all slots in ad server request with same slot id', function() { + var slotName = 'slot_same'; + var secondSlotSize = IndexUtils.supportedSizes[1]; + var configuredBids = [ + IndexUtils.createBidSlot(IndexUtils.DefaultPlacementCodePrefix, slotName, [ IndexUtils.supportedSizes[0] ]), + IndexUtils.createBidSlot(IndexUtils.DefaultPlacementCodePrefix, slotName, [ secondSlotSize ]), + ]; + adapter.callBids({ bids: configuredBids }); + assert.isTrue(adLoader.loadScript.called, 'loadScript get request'); + assert.include(adLoader.loadScript.firstCall.args[0], HeaderTagRequest, 'request is headertag request'); + + var requestJSON = IndexUtils.parseIndexRequest(adLoader.loadScript.firstCall.args[0]); + assert.isNotNull(requestJSON.r.imp, 'headertag request include impression object'); + + var impressionObj = requestJSON.r.imp; + + var expandedBids = configuredBids.map(bid => IndexUtils.expandSizes(bid)) + var sidMatched = IndexUtils.matchBidsOnSize(expandedBids, impressionObj); + for (var i = 0; i < sidMatched.matched.length; i++) { + var pair = sidMatched.matched[i]; + + var actualSlotID = pair.sent.ext.sid; + var expectedSlotID = pair.configured.params.id + '_1'; + assert.equal(actualSlotID, expectedSlotID, 'request ' + pair.name + ' slot ID is set to ' + expectedSlotID); + assert.isString(actualSlotID, 'slotID is string'); + } + + assert.equal(sidMatched.unmatched.sent.length, 0, 'All bids in impression object are from configured bids'); + + assert.equal(sidMatched.unmatched.configured.length, 1, 'All configured bids are in impression Obj'); + assert.equal(sidMatched.unmatched.configured[0].size, secondSlotSize, 'configured bid not in impression obj size width is' + JSON.stringify(secondSlotSize)); + assert.equal(sidMatched.unmatched.configured[0].params.id, slotName, 'slot name is ' + slotName); + }); + + var test_indexAdapter_siteid = [ + { + 'testname': 'test_prebid_indexAdapter_siteid_integer: site ID is integer -> siteID ID sent to AS as integer', + 'param': { 'siteID': 12345 }, + 'expected': 'pass', + }, + { + 'testname': 'test_prebid_indexAdapter_siteid_quoted_integer: site ID is quoted integer -> siteID ID sent to AS as integer', + 'param': { 'siteID': '12345' }, + 'expected': 'pass', + }, + { + 'testname': 'test_prebid_indexAdapter_siteid_float: site ID is float -> slot is ignored', + 'param': { 'siteID': 12.345 }, + 'expected': 'fail', + }, + { + 'testname': 'test_prebid_indexAdapter_siteid_string: site ID is string -> slot is ignored', + 'param': { 'siteID': 'string' }, + 'expected': 'fail', + }, + { + 'testname': 'test_prebid_indexAdapter_siteid_array: site ID is array with int -> siteID sent to AS as integer', + 'param': { 'siteID': [ 12345 ] }, + 'expected': 'pass', + }, + { + 'testname': 'test_prebid_indexAdapter_siteid_array: site ID is array with quoted int -> siteID sent to AS as integer', + 'param': { 'siteID': [ '12345' ] }, + 'expected': 'pass', + }, + { + 'testname': 'test_prebid_indexAdapter_siteid_array: site ID is array with alpha string -> slot is ignored', + 'param': { 'siteID': [ 'ABC' ] }, + 'expected': 'fail', + }, + { + 'testname': 'test_prebid_indexAdapter_siteid_hash: site ID is hash -> slot is ignored', + 'param': { 'siteID': { 12345: 678 } }, + 'expected': 'fail', + }, + { + 'testname': 'test_prebid_indexAdapter_siteid_zero: site ID is zero integer -> slot is ignored', + 'param': { 'siteID': 0 }, + 'expected': 'fail', + }, + { + 'testname': 'test_prebid_indexAdapter_siteid_negative: site ID is a negative integer -> slot is ignored', + 'param': { 'siteID': -1234 }, + 'expected': 'fail', + }, + { + 'testname': 'test_prebid_indexAdapter_siteid_missing: site ID is missing -> slot is ignored', + 'param': { 'missingSiteID': true }, + 'expected': 'invalid', + }, + ]; + + function base_prebid_indexAdapter_siteid (testname, param, expected) { + it(testname, function() { + var configuredBids = [ + IndexUtils.createBidSlot(IndexUtils.DefaultPlacementCodePrefix, 'slot_1', [ IndexUtils.supportedSizes[0] ], param), + ]; + + adapter.callBids({ bids: configuredBids }); + if (expected == 'pass') { + assert.isTrue(adLoader.loadScript.called, 'loadScript get request'); + assert.include(adLoader.loadScript.firstCall.args[0], HeaderTagRequest, 'request is headertag request'); + + var requestJSON = IndexUtils.parseIndexRequest(adLoader.loadScript.firstCall.args[0]); + assert.isNotNull(requestJSON.r.imp, 'headertag request include impression object'); + + var impressionObj = requestJSON.r.imp; + + var expandedBids = configuredBids.map(bid => IndexUtils.expandSizes(bid)) + var sidMatched = IndexUtils.matchBidsOnSID(expandedBids, impressionObj); + for (var i = 0; i < sidMatched.matched.length; i++) { + var pair = sidMatched.matched[i]; + + var actualSiteID = pair.sent.ext.siteID; + var expectedSiteID = pair.configured.params.siteID; + assert.equal(actualSiteID, expectedSiteID, 'request ' + pair.name + ' site ID is set to ' + expectedSiteID); + assert.isNumber(actualSiteID, 'site ID is integer'); + } + + assert.equal(sidMatched.unmatched.configured.length, 0, 'All configured bids are in impression Obj'); + assert.equal(sidMatched.unmatched.sent.length, 0, 'All bids in impression object are from configured bids'); + } else if (expected == 'invalid') { + // case where callBids throws out request due to missing params + assert.isFalse(adLoader.loadScript.called, 'No request to AS'); + } else { + assert.isUndefined(adLoader.loadScript.firstCall.args[0], 'No request to AS'); + } + }); + }; + + for (var i = 0; i < test_indexAdapter_siteid.length; i++) { + var test = test_indexAdapter_siteid[i]; + base_prebid_indexAdapter_siteid(test.testname, test.param, test.expected); + } + + // TS: case created by PBA-12 + it('test_prebid_indexAdapter_second_siteid_float: site ID is float -> slot is ignored', function() { + var configuredBids = [ + IndexUtils.createBidSlot(IndexUtils.DefaultPlacementCodePrefix + '1', 'slot_1', [ IndexUtils.supportedSizes[0] ]), + IndexUtils.createBidSlot(IndexUtils.DefaultPlacementCodePrefix + '2', 'slot_2', [ IndexUtils.supportedSizes[1] ], { 'siteID': 123.45 }), + ]; + + adapter.callBids({ bids: configuredBids }); + + assert.isTrue(adLoader.loadScript.called, 'loadScript get request'); + assert.include(adLoader.loadScript.firstCall.args[0], HeaderTagRequest, 'request is headertag request'); + + var requestJSON = IndexUtils.parseIndexRequest(adLoader.loadScript.firstCall.args[0]); + assert.isNotNull(requestJSON.r.imp, 'headertag request include impression object'); + + var impressionObj = requestJSON.r.imp; + + var expandedBids = configuredBids.map(bid => IndexUtils.expandSizes(bid)) + var sidMatched = IndexUtils.matchBidsOnSID(expandedBids, impressionObj); + assert.equal(sidMatched.matched.length, 1, 'one slot is configured and sent to AS'); + + for (var i = 0; i < sidMatched.matched.length; i++) { + var pair = sidMatched.matched[i]; + + var actualSiteID = pair.sent.ext.siteID; + var expectedSiteID = pair.configured.params.siteID; + assert.equal(actualSiteID, expectedSiteID, 'request ' + pair.name + ' site ID is set to ' + expectedSiteID); + assert.isNumber(actualSiteID, 'site ID is integer'); + } + + assert.equal(sidMatched.unmatched.configured.length, 1, 'float site ID configured bid is missing in impression Obj'); + assert.equal(sidMatched.unmatched.sent.length, 0, 'All bids in impression object are from configured bids'); + }); + + var test_indexAdapter_tier2siteid = [ + { + 'testname': 'test_prebid_indexAdapter_tier2siteid_integer: tier2 site ID is integer -> siteID ID sent to AS in integer', + 'param': { 'tier2SiteID': 12345 }, + 'expected': 'pass', + }, + { + 'testname': 'test_prebid_indexAdapter_tier2siteid_quoted_integer: tier2 site ID is quoted integer -> siteID ID sent to AS in integer', + 'param': { 'tier2SiteID': '12345' }, + 'expected': 'pass', + }, + { + 'testname': 'test_prebid_indexAdapter_tier2siteid_float: tier2 site ID is float -> slot is ignored', + 'param': { 'tier2SiteID': 12.345 }, + 'expected': 'fail', + }, + { + 'testname': 'test_prebid_indexAdapter_tier2siteid_string: tier2 site ID is string -> slot is ignored', + 'param': { 'tier2SiteID': 'string' }, + 'expected': 'fail', + }, + { + 'testname': 'test_prebid_indexAdapter_tier2siteid_array: tier2 site ID is array -> slot is ignored', + 'param': { 'tier2SiteID': [ 12345 ] }, + 'expected': 'pass', + }, + { + 'testname': 'test_prebid_indexAdapter_tier2siteid_hash: tier2 site ID is hash -> slot is ignored', + 'param': { 'tier2SiteID': { 12345: 678 } }, + 'expected': 'fail', + }, + { + 'testname': 'test_prebid_indexAdapter_tier2siteid_zero: tier2 site ID is zero integer -> slot is ignored', + 'param': { 'tier2SiteID': 0 }, + 'expected': 'fail', + }, + { + 'testname': 'test_prebid_indexAdapter_tier2siteid_negative: tier2 site ID is a negative integer -> slot is ignored', + 'param': { 'tier2SiteID': -1234 }, + 'expected': 'fail', + }, + { + 'testname': 'test_prebid_indexAdapter_tier2siteid_missing: tier2 site ID is missing -> slot is ignored', + 'param': { 'missingtier2SiteID': true }, + 'expected': 'fail', + }, + ]; + function base_prebid_indexAdapter_tier2siteid (testname, param, expected) { + it(testname, function() { + var configuredBids = [ + IndexUtils.createBidSlot(IndexUtils.DefaultPlacementCodePrefix, 'slot_1', [ IndexUtils.supportedSizes[0] ], param), + ]; + adapter.callBids({ bids: configuredBids }); + + assert.isTrue(adLoader.loadScript.called, 'loadScript get request'); + assert.include(adLoader.loadScript.firstCall.args[0], HeaderTagRequest, 'request is headertag request'); + + var requestJSON = IndexUtils.parseIndexRequest(adLoader.loadScript.firstCall.args[0]); + assert.isNotNull(requestJSON.r.imp, 'headertag request include impression object'); + + var impressionObj = requestJSON.r.imp; + var expandedBids = configuredBids.map(bid => IndexUtils.expandSizes(bid)) + var sidMatched = IndexUtils.matchBidsOnSID(expandedBids, impressionObj); + + if (expected == 'pass') { + assert.equal(sidMatched.matched.length, 2, 'Two slots are configured and sent to AS'); + + // check normal site id + var normalSitePair = sidMatched.matched[0]; + + var expectedSlotID = normalSitePair.configured.params.id + '_1'; + assert.equal(normalSitePair.sent.ext.sid, expectedSlotID, 'request ' + normalSitePair.name + ' site ID is set to ' + expectedSlotID); + assert.isString(normalSitePair.sent.ext.sid, 'type of slot ID is string'); + + var expectedSiteID = normalSitePair.configured.params.siteID; + assert.equal(normalSitePair.sent.ext.siteID, expectedSiteID, 'request ' + normalSitePair.name + ' site ID is set to ' + expectedSiteID); + assert.isNumber(normalSitePair.sent.ext.siteID, 'site ID is integer'); + + // check tier site id + var tier2SitePair = sidMatched.matched[1]; + var expectedTierSlotID = 'T1_' + tier2SitePair.configured.params.id + '_1'; + assert.equal(tier2SitePair.sent.ext.sid, expectedTierSlotID, 'request ' + tier2SitePair.name + ' site ID is set to ' + expectedTierSlotID); + assert.isString(tier2SitePair.sent.ext.sid, 'type of slot ID is string'); + + var expectedTierSiteID = tier2SitePair.configured.params.tier2SiteID; + assert.equal(tier2SitePair.sent.ext.siteID, expectedTierSiteID, 'request ' + normalSitePair.name + ' site ID is set to ' + expectedTierSiteID); + assert.isNumber(tier2SitePair.sent.ext.siteID, 'site ID is integer'); + + // check unsent bids + assert.equal(sidMatched.unmatched.configured.length, 0, 'All configured bids are in impression Obj'); + assert.equal(sidMatched.unmatched.sent.length, 0, 'All bids in impression object are from configured bids'); + } else { + assert.equal(sidMatched.matched.length, 1, 'one slot is configured and sent to AS'); + + // check normal site id + var normalSitePair = sidMatched.matched[0]; + + var expectedSlotID = normalSitePair.configured.params.id + '_1'; + assert.equal(normalSitePair.sent.ext.sid, expectedSlotID, 'request ' + normalSitePair.name + ' site ID is set to ' + expectedSlotID); + assert.isString(normalSitePair.sent.ext.sid, 'type of slot ID is string'); + + var expectedSiteID = normalSitePair.configured.params.siteID; + assert.equal(normalSitePair.sent.ext.siteID, expectedSiteID, 'request ' + normalSitePair.name + ' site ID is set to ' + expectedSiteID); + assert.isNumber(normalSitePair.sent.ext.siteID, 'site ID is integer'); + + // check unsent bids + if (param.missingtier2SiteID) { + assert.equal(sidMatched.unmatched.configured.length, 0, 'one configured bid is missing in impression Obj'); + } else { + assert.equal(sidMatched.unmatched.configured.length, 1, 'one configured bid is missing in impression Obj'); + } + assert.equal(sidMatched.unmatched.sent.length, 0, 'All bids in impression object are from configured bids'); + } + }); + }; + + for (var i = 0; i < test_indexAdapter_tier2siteid.length; i++) { + var test = test_indexAdapter_tier2siteid[i]; + base_prebid_indexAdapter_tier2siteid(test.testname, test.param, test.expected); + } + + var test_indexAdapter_tier3siteid = [ + { + 'testname': 'test_prebid_indexAdapter_tier3siteid_integer: tier3 site ID is integer -> siteID ID sent to AS in integer', + 'param': { 'tier3SiteID': 12345 }, + 'expected': 'pass', + }, + { + 'testname': 'test_prebid_indexAdapter_tier3siteid_quoted_integer: tier3 site ID is quoted integer -> siteID ID sent to AS in integer', + 'param': { 'tier3SiteID': '12345' }, + 'expected': 'pass', + }, + { + 'testname': 'test_prebid_indexAdapter_tier3siteid_float: tier3 site ID is float -> slot is ignored', + 'param': { 'tier3SiteID': 12.345 }, + 'expected': 'fail', + }, + { + 'testname': 'test_prebid_indexAdapter_tier3siteid_string: tier3 site ID is string -> slot is ignored', + 'param': { 'tier3SiteID': 'string' }, + 'expected': 'fail', + }, + { + 'testname': 'test_prebid_indexAdapter_tier3siteid_array: tier3 site ID is array -> slot is ignored', + 'param': { 'tier3SiteID': [ 12345 ] }, + 'expected': 'pass', + }, + { + 'testname': 'test_prebid_indexAdapter_tier3siteid_hash: tier3 site ID is hash -> slot is ignored', + 'param': { 'tier3SiteID': { 12345: 678 } }, + 'expected': 'fail', + }, + { + 'testname': 'test_prebid_indexAdapter_tier3siteid_zero: tier3 site ID is zero integer -> slot is ignored', + 'param': { 'tier3SiteID': 0 }, + 'expected': 'fail', + }, + { + 'testname': 'test_prebid_indexAdapter_tier3siteid_negative: tier3 site ID is a negative integer -> slot is ignored', + 'param': { 'tier3SiteID': -1234 }, + 'expected': 'fail', + }, + { + 'testname': 'test_prebid_indexAdapter_tier3siteid_missing: tier3 site ID is missing -> slot is ignored', + 'param': { 'missingtier3SiteID': true }, + 'expected': 'fail', + }, + ]; + function base_prebid_indexAdapter_tier3siteid (testname, param, expected) { + it(testname, function() { + var configuredBids = [ + IndexUtils.createBidSlot(IndexUtils.DefaultPlacementCodePrefix, 'slot_1', [ IndexUtils.supportedSizes[0] ], param), + ]; + adapter.callBids({ bids: configuredBids }); + + assert.isTrue(adLoader.loadScript.called, 'loadScript get request'); + assert.include(adLoader.loadScript.firstCall.args[0], HeaderTagRequest, 'request is headertag request'); + + var requestJSON = IndexUtils.parseIndexRequest(adLoader.loadScript.firstCall.args[0]); + assert.isNotNull(requestJSON.r.imp, 'headertag request include impression object'); + + var impressionObj = requestJSON.r.imp; + var expandedBids = configuredBids.map(bid => IndexUtils.expandSizes(bid)) + var sidMatched = IndexUtils.matchBidsOnSID(expandedBids, impressionObj); + + if (expected == 'pass') { + assert.equal(sidMatched.matched.length, 2, 'Two slots are configured and sent to AS'); + + // check normal site id + var normalSitePair = sidMatched.matched[0]; + + var expectedSlotID = normalSitePair.configured.params.id + '_1'; + assert.equal(normalSitePair.sent.ext.sid, expectedSlotID, 'request ' + normalSitePair.name + ' site ID is set to ' + expectedSlotID); + assert.isString(normalSitePair.sent.ext.sid, 'type of slot ID is string'); + + var expectedSiteID = normalSitePair.configured.params.siteID; + assert.equal(normalSitePair.sent.ext.siteID, expectedSiteID, 'request ' + normalSitePair.name + ' site ID is set to ' + expectedSiteID); + assert.isNumber(normalSitePair.sent.ext.siteID, 'site ID is integer'); + + // check tier site id + var tier3SitePair = sidMatched.matched[1]; + var expectedTierSlotID = 'T2_' + tier3SitePair.configured.params.id + '_1'; + assert.equal(tier3SitePair.sent.ext.sid, expectedTierSlotID, 'request ' + tier3SitePair.name + ' site ID is set to ' + expectedTierSlotID); + assert.isString(tier3SitePair.sent.ext.sid, 'type of slot ID is string'); + + var expectedTierSiteID = tier3SitePair.configured.params.tier3SiteID; + assert.equal(tier3SitePair.sent.ext.siteID, expectedTierSiteID, 'request ' + normalSitePair.name + ' site ID is set to ' + expectedTierSiteID); + assert.isNumber(tier3SitePair.sent.ext.siteID, 'site ID is integer'); + + // check unsent bids + assert.equal(sidMatched.unmatched.configured.length, 0, 'All configured bids are in impression Obj'); + assert.equal(sidMatched.unmatched.sent.length, 0, 'All bids in impression object are from configured bids'); + } else { + assert.equal(sidMatched.matched.length, 1, 'one slot is configured and sent to AS'); + + // check normal site id + var normalSitePair = sidMatched.matched[0]; + + var expectedSlotID = normalSitePair.configured.params.id + '_1'; + assert.equal(normalSitePair.sent.ext.sid, expectedSlotID, 'request ' + normalSitePair.name + ' site ID is set to ' + expectedSlotID); + assert.isString(normalSitePair.sent.ext.sid, 'type of slot ID is string'); + + var expectedSiteID = normalSitePair.configured.params.siteID; + assert.equal(normalSitePair.sent.ext.siteID, expectedSiteID, 'request ' + normalSitePair.name + ' site ID is set to ' + expectedSiteID); + assert.isNumber(normalSitePair.sent.ext.siteID, 'site ID is integer'); + + // check unsent bids + if (param.missingtier3SiteID) { + assert.equal(sidMatched.unmatched.configured.length, 0, 'one configured bid is missing in impression Obj'); + } else { + assert.equal(sidMatched.unmatched.configured.length, 1, 'one configured bid is missing in impression Obj'); + } + assert.equal(sidMatched.unmatched.sent.length, 0, 'All bids in impression object are from configured bids'); + } + }); + }; + + for (var i = 0; i < test_indexAdapter_tier3siteid.length; i++) { + var test = test_indexAdapter_tier3siteid[i]; + base_prebid_indexAdapter_tier3siteid(test.testname, test.param, test.expected); + } + + it('test_prebid_indexAdapter_siteID_multiple: multiple slots have same siteIDs -> all slots in ad server request with the same site IDs', function() { + var first_slot = { + slotName: 'slot1', + siteID: 111111, + }; + var second_slot = { + slotName: 'slot2', + siteID: 111111, // same as first slot + }; + + var configuredBids = [ + IndexUtils.createBidSlot(IndexUtils.DefaultPlacementCodePrefix, first_slot['slotName'], [ IndexUtils.supportedSizes[0] ], { siteID: first_slot['siteID'] }), + IndexUtils.createBidSlot(IndexUtils.DefaultPlacementCodePrefix, second_slot['slotName'], [ IndexUtils.supportedSizes[1] ], { siteID: second_slot['siteID'] }), + ]; + + adapter.callBids({ bids: configuredBids }); + var requestJSON = IndexUtils.parseIndexRequest(adLoader.loadScript.firstCall.args[0]); + assert.isNotNull(requestJSON.r.imp, 'headertag request include impression object'); + + var impressionObj = requestJSON.r.imp; + + var expandedBids = configuredBids.map(bid => IndexUtils.expandSizes(bid)) + var sidMatched = IndexUtils.matchBidsOnSize(expandedBids, impressionObj); + for (var i = 0; i < sidMatched.matched.length; i++) { + var pair = sidMatched.matched[i]; + + var expectedSiteID = pair.configured.params.siteID; + var actualSiteID = pair.sent.ext.siteID; + assert.equal(actualSiteID, expectedSiteID, 'request ' + pair.name + ' site ID is set to ' + expectedSiteID); + assert.isNumber(actualSiteID, 'site ID is number'); + } + + assert.equal(sidMatched.unmatched.sent.length, 0, 'All bids in impression object are from configured bids'); + assert.equal(sidMatched.unmatched.configured.length, 0, 'All configured bids are in impression Obj'); + }); + + it('test_prebid_indexAdapter_siteID_different: multiple slots have different siteIDs -> all slots in ad server request with the different site IDs', function() { + var first_slot = { + slotName: 'slot1', + siteID: 111111, + }; + var second_slot = { + slotName: 'slot2', + siteID: 222222, + }; + + var configuredBids = [ + IndexUtils.createBidSlot(IndexUtils.DefaultPlacementCodePrefix, first_slot['slotName'], [ IndexUtils.supportedSizes[0] ], { siteID: first_slot['siteID'] }), + IndexUtils.createBidSlot(IndexUtils.DefaultPlacementCodePrefix, second_slot['slotName'], [ IndexUtils.supportedSizes[1] ], { siteID: second_slot['siteID'] }), + ]; + + adapter.callBids({ bids: configuredBids }); + var requestJSON = IndexUtils.parseIndexRequest(adLoader.loadScript.firstCall.args[0]); + assert.isNotNull(requestJSON.r.imp, 'headertag request include impression object'); + + var impressionObj = requestJSON.r.imp; + + var expandedBids = configuredBids.map(bid => IndexUtils.expandSizes(bid)) + var sidMatched = IndexUtils.matchBidsOnSize(expandedBids, impressionObj); + for (var i = 0; i < sidMatched.matched.length; i++) { + var pair = sidMatched.matched[i]; + + var expectedSiteID = pair.configured.params.siteID; + var actualSiteID = pair.sent.ext.siteID; + assert.equal(actualSiteID, expectedSiteID, 'request ' + pair.name + ' site ID is set to ' + expectedSiteID); + assert.isNumber(actualSiteID, 'site ID is number'); + } + + assert.equal(sidMatched.unmatched.sent.length, 0, 'All bids in impression object are from configured bids'); + assert.equal(sidMatched.unmatched.configured.length, 0, 'All configured bids are in impression Obj'); + }); + + it('test_prebid_indexAdapter_size_singleArr: single sized array -> width and height in integer in request', function () { + var configuredBids = [ + IndexUtils.createBidSlot(IndexUtils.DefaultPlacementCodePrefix, 'slot_1', IndexUtils.supportedSizes[0]) + ]; + adapter.callBids({ bids: configuredBids }); + + assert.isTrue(adLoader.loadScript.called, 'loadScript get request'); + + assert.include(adLoader.loadScript.firstCall.args[0], HeaderTagRequest, 'request is headertag request'); + + var requestJSON = IndexUtils.parseIndexRequest(adLoader.loadScript.firstCall.args[0]); + assert.isNotNull(requestJSON.r.imp, 'headertag request include impression object'); + + var impressionObj = requestJSON.r.imp; + + var expandedBids = configuredBids.map(bid => IndexUtils.expandSizes(bid)) + var sidMatched = IndexUtils.matchBidsOnSID(expandedBids, impressionObj); + for (var i = 0; i < sidMatched.matched.length; i++) { + var pair = sidMatched.matched[i]; + + assert.equal(pair.sent.banner.w, pair.configured.size[0], 'request ' + pair.name + ' width is set to ' + pair.configured.size[0]); + assert.equal(pair.sent.banner.h, pair.configured.size[1], 'request ' + pair.name + ' width is set to ' + pair.configured.size[1]); + assert.equal(pair.sent.ext.siteID, pair.configured.params.siteID, 'request ' + pair.name + ' siteID is set to ' + pair.configured.params.siteID); + } + + assert.equal(sidMatched.unmatched.configured.length, 0, 'All configured bids are in impression Obj'); + assert.equal(sidMatched.unmatched.sent.length, 0, 'All bids in impression object are from configured bids'); + }); + + it('test_prebid_indexAdapter_size_singleDim: missing width/height -> size is ignored, no ad server request for bad size', function () { + var oneDimSize = [728]; + var configuredBids = [ + IndexUtils.createBidSlot(IndexUtils.DefaultPlacementCodePrefix, 'slot_1', [ IndexUtils.supportedSizes[0], oneDimSize, IndexUtils.supportedSizes[1] ]) + ]; + adapter.callBids({ bids: configuredBids }); + + assert.isTrue(adLoader.loadScript.called, 'loadScript get request'); + assert.include(adLoader.loadScript.firstCall.args[0], HeaderTagRequest, 'request is headertag request'); + + var requestJSON = IndexUtils.parseIndexRequest(adLoader.loadScript.firstCall.args[0]); + assert.isNotNull(requestJSON.r.imp, 'headertag request include impression object'); + + var impressionObj = requestJSON.r.imp; + + var expandedBids = configuredBids.map(bid => IndexUtils.expandSizes(bid)) + var sidMatched = IndexUtils.matchBidsOnSize(expandedBids, impressionObj); + + for (var i = 0; i < sidMatched.matched.length; i++) { + var pair = sidMatched.matched[i]; + + assert.equal(pair.sent.banner.w, pair.configured.size[0], 'request ' + pair.name + ' width is set to ' + pair.configured.size[0]); + assert.equal(pair.sent.banner.h, pair.configured.size[1], 'request ' + pair.name + ' width is set to ' + pair.configured.size[1]); + assert.equal(pair.sent.ext.siteID, pair.configured.params.siteID, 'request ' + pair.name + ' siteID is set to ' + pair.configured.params.siteID); + } + + assert.equal(sidMatched.unmatched.sent.length, 0, 'All bids in impression object are from configured bids'); + assert.equal(sidMatched.unmatched.configured.length, 1, '1 configured bid is not in impression Obj'); + assert.equal(sidMatched.unmatched.configured[0].size, oneDimSize, 'configured bid not in impression obj size width is' + JSON.stringify(oneDimSize)); + }); + + it('test_prebid_indexAdapter_size_missing: missing size -> slot is ignored, no ad server request', function () { + var configuredBids = [ + IndexUtils.createBidSlot(IndexUtils.DefaultPlacementCodePrefix, 'slot_1', []) + ]; + adapter.callBids({ bids: configuredBids }); + + assert.isUndefined(adLoader.loadScript.firstCall.args[0], 'no request made to AS'); + }); + + it('test_prebid_indexAdapter_size_negativeWidth: negative width -> size is ignored, no ad server request for bad size', function () { + var invalidSize = [-728, 90]; + var configuredBids = [ + IndexUtils.createBidSlot(IndexUtils.DefaultPlacementCodePrefix, 'slot_1', [ IndexUtils.supportedSizes[0], invalidSize, IndexUtils.supportedSizes[1] ]) + ]; + adapter.callBids({ bids: configuredBids }); + + assert.isTrue(adLoader.loadScript.called, 'loadScript get request'); + assert.include(adLoader.loadScript.firstCall.args[0], HeaderTagRequest, 'request is headertag request'); + + var requestJSON = IndexUtils.parseIndexRequest(adLoader.loadScript.firstCall.args[0]); + assert.isNotNull(requestJSON.r.imp, 'headertag request include impression object'); + + var impressionObj = requestJSON.r.imp; + + var expandedBids = configuredBids.map(bid => IndexUtils.expandSizes(bid)) + var sidMatched = IndexUtils.matchBidsOnSize(expandedBids, impressionObj); + + for (var i = 0; i < sidMatched.matched.length; i++) { + var pair = sidMatched.matched[i]; + + assert.equal(pair.sent.banner.w, pair.configured.size[0], 'request ' + pair.name + ' width is set to ' + pair.configured.size[0]); + assert.equal(pair.sent.banner.h, pair.configured.size[1], 'request ' + pair.name + ' width is set to ' + pair.configured.size[1]); + assert.equal(pair.sent.ext.siteID, pair.configured.params.siteID, 'request ' + pair.name + ' siteID is set to ' + pair.configured.params.siteID); + } + + assert.equal(sidMatched.unmatched.sent.length, 0, 'All bids in impression object are from configured bids'); + assert.equal(sidMatched.unmatched.configured.length, 1, '1 configured bid is not in impression Obj'); + assert.equal(sidMatched.unmatched.configured[0].size, invalidSize, 'configured bid not in impression obj size width is' + JSON.stringify(invalidSize)); + }); + + it('test_prebid_indexAdapter_size_negativeHeight: negative height -> size is ignored, no ad server request for bad size', function () { + var invalidSize = [728, -90]; + var configuredBids = [ + IndexUtils.createBidSlot(IndexUtils.DefaultPlacementCodePrefix, 'slot_1', [ IndexUtils.supportedSizes[0], invalidSize, IndexUtils.supportedSizes[1] ]) + ]; + adapter.callBids({ bids: configuredBids }); + + assert.isTrue(adLoader.loadScript.called, 'loadScript get request'); + assert.include(adLoader.loadScript.firstCall.args[0], HeaderTagRequest, 'request is headertag request'); + + var requestJSON = IndexUtils.parseIndexRequest(adLoader.loadScript.firstCall.args[0]); + assert.isNotNull(requestJSON.r.imp, 'headertag request include impression object'); + + var impressionObj = requestJSON.r.imp; + + var expandedBids = configuredBids.map(bid => IndexUtils.expandSizes(bid)) + var sidMatched = IndexUtils.matchBidsOnSize(expandedBids, impressionObj); + + for (var i = 0; i < sidMatched.matched.length; i++) { + var pair = sidMatched.matched[i]; + + assert.equal(pair.sent.banner.w, pair.configured.size[0], 'request ' + pair.name + ' width is set to ' + pair.configured.size[0]); + assert.equal(pair.sent.banner.h, pair.configured.size[1], 'request ' + pair.name + ' width is set to ' + pair.configured.size[1]); + assert.equal(pair.sent.ext.siteID, pair.configured.params.siteID, 'request ' + pair.name + ' siteID is set to ' + pair.configured.params.siteID); + } + + assert.equal(sidMatched.unmatched.sent.length, 0, 'All bids in impression object are from configured bids'); + assert.equal(sidMatched.unmatched.configured.length, 1, '1 configured bid is not in impression Obj'); + assert.equal(sidMatched.unmatched.configured[0].size, invalidSize, 'configured bid not in impression obj size width is' + JSON.stringify(invalidSize)); + }); + + it('test_prebid_indexAdapter_size_quoted: height and width quoted -> invalid size, no ad server request for invalid size', function () { + var otherSize = ['300', '250']; + var configuredBids = [ + IndexUtils.createBidSlot(IndexUtils.DefaultPlacementCodePrefix, 'slot_1', [ IndexUtils.supportedSizes[0], otherSize, IndexUtils.supportedSizes[1] ]) + ]; + adapter.callBids({ bids: configuredBids }); + + assert.isTrue(adLoader.loadScript.called, 'loadScript get request'); + assert.include(adLoader.loadScript.firstCall.args[0], HeaderTagRequest, 'request is headertag request'); + + var requestJSON = IndexUtils.parseIndexRequest(adLoader.loadScript.firstCall.args[0]); + assert.isNotNull(requestJSON.r.imp, 'headertag request include impression object'); + + var impressionObj = requestJSON.r.imp; + + var expandedBids = configuredBids.map(bid => IndexUtils.expandSizes(bid)); + var sidMatched = IndexUtils.matchBidsOnSize(expandedBids, impressionObj); + + for (var i = 0; i < sidMatched.matched.length; i++) { + var pair = sidMatched.matched[i]; + + assert.equal(pair.sent.banner.w, pair.configured.size[0], 'request ' + pair.name + ' width is set to ' + pair.configured.size[0]); + assert.equal(pair.sent.banner.h, pair.configured.size[1], 'request ' + pair.name + ' width is set to ' + pair.configured.size[1]); + assert.equal(pair.sent.ext.siteID, pair.configured.params.siteID, 'request ' + pair.name + ' siteID is set to ' + pair.configured.params.siteID); + } + + assert.equal(sidMatched.unmatched.sent.length, 0, 'All bids in impression object are from configured bids'); + assert.equal(sidMatched.unmatched.configured.length, 0, '0 configured bid is not in impression Obj'); + }); + + it('test_prebid_indexAdapter_size_float: height and width float -> invalid size, no ad server request for invalid size ', function () { + var otherSize = [300.1, 250]; + var configuredBids = [ + IndexUtils.createBidSlot(IndexUtils.DefaultPlacementCodePrefix, 'slot_1', [ IndexUtils.supportedSizes[0], otherSize, IndexUtils.supportedSizes[1] ]) + ]; + adapter.callBids({ bids: configuredBids }); + + assert.isTrue(adLoader.loadScript.called, 'loadScript get request'); + assert.include(adLoader.loadScript.firstCall.args[0], HeaderTagRequest, 'request is headertag request'); + + var requestJSON = IndexUtils.parseIndexRequest(adLoader.loadScript.firstCall.args[0]); + assert.isNotNull(requestJSON.r.imp, 'headertag request include impression object'); + + var impressionObj = requestJSON.r.imp; + + var expandedBids = configuredBids.map(bid => IndexUtils.expandSizes(bid)); + var sidMatched = IndexUtils.matchBidsOnSize(expandedBids, impressionObj); + + for (var i = 0; i < sidMatched.matched.length; i++) { + var pair = sidMatched.matched[i]; + + assert.equal(pair.sent.banner.w, pair.configured.size[0], 'request ' + pair.name + ' width is set to ' + pair.configured.size[0]); + assert.equal(pair.sent.banner.h, pair.configured.size[1], 'request ' + pair.name + ' width is set to ' + pair.configured.size[1]); + assert.equal(pair.sent.ext.siteID, pair.configured.params.siteID, 'request ' + pair.name + ' siteID is set to ' + pair.configured.params.siteID); + } + + assert.equal(sidMatched.unmatched.sent.length, 0, 'All bids in impression object are from configured bids'); + assert.equal(sidMatched.unmatched.configured.length, 1, '1 configured bid is not in impression Obj'); + assert.equal(sidMatched.unmatched.configured[0].size, otherSize, 'configured bid not in impression obj size width is' + JSON.stringify(otherSize)); + }); + + it('test_prebid_indexAdapter_size_string_1_pba23: height and width string -> invalid size, no ad server request for invalid size ', function () { + var otherSize = [String(IndexUtils.supportedSizes[0][0]), String(IndexUtils.supportedSizes[0][1])]; + var configuredBids = [ + IndexUtils.createBidSlot(IndexUtils.DefaultPlacementCodePrefix, 'slot_1', [ IndexUtils.supportedSizes[1], otherSize, IndexUtils.supportedSizes[2] ]) + ]; + adapter.callBids({ bids: configuredBids }); + + assert.isTrue(adLoader.loadScript.called, 'loadScript get request'); + assert.include(adLoader.loadScript.firstCall.args[0], HeaderTagRequest, 'request is headertag request'); + + var requestJSON = IndexUtils.parseIndexRequest(adLoader.loadScript.firstCall.args[0]); + assert.isNotNull(requestJSON.r.imp, 'headertag request include impression object'); + + var impressionObj = requestJSON.r.imp; + + var expandedBids = configuredBids.map(bid => IndexUtils.expandSizes(bid)); + var sidMatched = IndexUtils.matchBidsOnSize(expandedBids, impressionObj); + + for (var i = 0; i < sidMatched.matched.length; i++) { + var pair = sidMatched.matched[i]; + + assert.equal(pair.sent.banner.w, pair.configured.size[0], 'request ' + pair.name + ' width is set to ' + pair.configured.size[0]); + assert.equal(pair.sent.banner.h, pair.configured.size[1], 'request ' + pair.name + ' width is set to ' + pair.configured.size[1]); + assert.equal(pair.sent.ext.siteID, pair.configured.params.siteID, 'request ' + pair.name + ' siteID is set to ' + pair.configured.params.siteID); + } + + assert.equal(sidMatched.unmatched.sent.length, 0, 'All bids in impression object are from configured bids'); + assert.equal(sidMatched.unmatched.configured.length, 0, 'all configured bids are in impression Obj'); + }); + + it('test_prebid_indexAdapter_size_string_2: whole size is string -> invalid size, no ad server request for invalid size ', function () { + var otherSize = 'gallery'; + var configuredBids = [ + IndexUtils.createBidSlot(IndexUtils.DefaultPlacementCodePrefix, 'slot_1', [ IndexUtils.supportedSizes[0], otherSize, IndexUtils.supportedSizes[1] ]) + ]; + adapter.callBids({ bids: configuredBids }); + + assert.isTrue(adLoader.loadScript.called, 'loadScript get request'); + assert.include(adLoader.loadScript.firstCall.args[0], HeaderTagRequest, 'request is headertag request'); + + var requestJSON = IndexUtils.parseIndexRequest(adLoader.loadScript.firstCall.args[0]); + assert.isNotNull(requestJSON.r.imp, 'headertag request include impression object'); + + var impressionObj = requestJSON.r.imp; + + var expandedBids = configuredBids.map(bid => IndexUtils.expandSizes(bid)); + var sidMatched = IndexUtils.matchBidsOnSize(expandedBids, impressionObj); + + for (var i = 0; i < sidMatched.matched.length; i++) { + var pair = sidMatched.matched[i]; + + assert.equal(pair.sent.banner.w, pair.configured.size[0], 'request ' + pair.name + ' width is set to ' + pair.configured.size[0]); + assert.equal(pair.sent.banner.h, pair.configured.size[1], 'request ' + pair.name + ' width is set to ' + pair.configured.size[1]); + assert.equal(pair.sent.ext.siteID, pair.configured.params.siteID, 'request ' + pair.name + ' siteID is set to ' + pair.configured.params.siteID); + } + + assert.equal(sidMatched.unmatched.sent.length, 0, 'All bids in impression object are from configured bids'); + assert.equal(sidMatched.unmatched.configured.length, 1, '1 configured bid is not in impression Obj'); + assert.equal(sidMatched.unmatched.configured[0].size, otherSize, 'configured bid not in impression obj size width is' + JSON.stringify(otherSize)); + }); + + it('test_prebid_indexAdapter_size_string_3: entire size structure is string -> no ad server request since size is invalid', function () { + var configuredBids = [ + IndexUtils.createBidSlot(IndexUtils.DefaultPlacementCodePrefix, 'slot_1', 'gallery') + ]; + adapter.callBids({ bids: configuredBids }); + + assert.isUndefined(adLoader.loadScript.firstCall.args[0], 'no request made to AS'); + }); + + it('test_prebid_indexAdapter_size_hash_1: height or width hash -> invalid size, no ad server request for invalid size ', function () { + var otherSize = [{728: 1}, 90]; + var configuredBids = [ + IndexUtils.createBidSlot(IndexUtils.DefaultPlacementCodePrefix, 'slot_1', [ IndexUtils.supportedSizes[0], otherSize, IndexUtils.supportedSizes[1] ]) + ]; + adapter.callBids({ bids: configuredBids }); + + assert.isTrue(adLoader.loadScript.called, 'loadScript get request'); + assert.include(adLoader.loadScript.firstCall.args[0], HeaderTagRequest, 'request is headertag request'); + + var requestJSON = IndexUtils.parseIndexRequest(adLoader.loadScript.firstCall.args[0]); + assert.isNotNull(requestJSON.r.imp, 'headertag request include impression object'); + + var impressionObj = requestJSON.r.imp; + + var expandedBids = configuredBids.map(bid => IndexUtils.expandSizes(bid)); + var sidMatched = IndexUtils.matchBidsOnSize(expandedBids, impressionObj); + + for (var i = 0; i < sidMatched.matched.length; i++) { + var pair = sidMatched.matched[i]; + + assert.equal(pair.sent.banner.w, pair.configured.size[0], 'request ' + pair.name + ' width is set to ' + pair.configured.size[0]); + assert.equal(pair.sent.banner.h, pair.configured.size[1], 'request ' + pair.name + ' width is set to ' + pair.configured.size[1]); + assert.equal(pair.sent.ext.siteID, pair.configured.params.siteID, 'request ' + pair.name + ' siteID is set to ' + pair.configured.params.siteID); + } + + assert.equal(sidMatched.unmatched.sent.length, 0, 'All bids in impression object are from configured bids'); + assert.equal(sidMatched.unmatched.configured.length, 1, '1 configured bid is not in impression Obj'); + assert.equal(sidMatched.unmatched.configured[0].size, otherSize, 'configured bid not in impression obj size width is' + JSON.stringify(otherSize)); + }); + + it('test_prebid_indexAdapter_size_hash_2: whole size hash -> invalid size, no ad server request for invalid size ', function () { + var otherSize = {728: 1, 90: 1}; + var configuredBids = [ + IndexUtils.createBidSlot(IndexUtils.DefaultPlacementCodePrefix, 'slot_1', [ IndexUtils.supportedSizes[0], otherSize, IndexUtils.supportedSizes[1] ]) + ]; + adapter.callBids({ bids: configuredBids }); + + assert.isTrue(adLoader.loadScript.called, 'loadScript get request'); + assert.include(adLoader.loadScript.firstCall.args[0], HeaderTagRequest, 'request is headertag request'); + + var requestJSON = IndexUtils.parseIndexRequest(adLoader.loadScript.firstCall.args[0]); + assert.isNotNull(requestJSON.r.imp, 'headertag request include impression object'); + + var impressionObj = requestJSON.r.imp; + + var expandedBids = configuredBids.map(bid => IndexUtils.expandSizes(bid)); + var sidMatched = IndexUtils.matchBidsOnSize(expandedBids, impressionObj); + + for (var i = 0; i < sidMatched.matched.length; i++) { + var pair = sidMatched.matched[i]; + + assert.equal(pair.sent.banner.w, pair.configured.size[0], 'request ' + pair.name + ' width is set to ' + pair.configured.size[0]); + assert.equal(pair.sent.banner.h, pair.configured.size[1], 'request ' + pair.name + ' width is set to ' + pair.configured.size[1]); + assert.equal(pair.sent.ext.siteID, pair.configured.params.siteID, 'request ' + pair.name + ' siteID is set to ' + pair.configured.params.siteID); + } + + assert.equal(sidMatched.unmatched.sent.length, 0, 'All bids in impression object are from configured bids'); + assert.equal(sidMatched.unmatched.configured.length, 1, '1 configured bid is not in impression Obj'); + assert.equal(sidMatched.unmatched.configured[0].size, otherSize, 'configured bid not in impression obj size width is' + JSON.stringify(otherSize)); + }); + + it('test_prebid_indexAdapter_size_hash_3: entire size structure is hash -> no ad server request since size is invalid', function () { + var configuredBids = [ + IndexUtils.createBidSlot(IndexUtils.DefaultPlacementCodePrefix, 'slot_1', {728: 90}) + ]; + adapter.callBids({ bids: configuredBids }); + + assert.isUndefined(adLoader.loadScript.firstCall.args[0], 'no request made to AS'); + }); + + it('test_prebid_indexAdapter_size_swap: swap size and width for valid so now its invalid -> unsupportedsize, no ad server request for unsupported size ', function () { + var otherSize = [90, 728]; + var configuredBids = [ + IndexUtils.createBidSlot(IndexUtils.DefaultPlacementCodePrefix, 'slot_1', [ IndexUtils.supportedSizes[0], otherSize, IndexUtils.supportedSizes[1] ]) + ]; + adapter.callBids({ bids: configuredBids }); + + assert.isTrue(adLoader.loadScript.called, 'loadScript get request'); + assert.include(adLoader.loadScript.firstCall.args[0], HeaderTagRequest, 'request is headertag request'); + + var requestJSON = IndexUtils.parseIndexRequest(adLoader.loadScript.firstCall.args[0]); + assert.isNotNull(requestJSON.r.imp, 'headertag request include impression object'); + + var impressionObj = requestJSON.r.imp; + + var expandedBids = configuredBids.map(bid => IndexUtils.expandSizes(bid)); + var sidMatched = IndexUtils.matchBidsOnSize(expandedBids, impressionObj); + + for (var i = 0; i < sidMatched.matched.length; i++) { + var pair = sidMatched.matched[i]; + + assert.equal(pair.sent.banner.w, pair.configured.size[0], 'request ' + pair.name + ' width is set to ' + pair.configured.size[0]); + assert.equal(pair.sent.banner.h, pair.configured.size[1], 'request ' + pair.name + ' width is set to ' + pair.configured.size[1]); + assert.equal(pair.sent.ext.siteID, pair.configured.params.siteID, 'request ' + pair.name + ' siteID is set to ' + pair.configured.params.siteID); + } + + assert.equal(sidMatched.unmatched.sent.length, 0, 'All bids in impression object are from configured bids'); + assert.equal(sidMatched.unmatched.configured.length, 1, '1 configured bid is not in impression Obj'); + assert.equal(sidMatched.unmatched.configured[0].size, otherSize, 'configured bid not in impression obj size width is' + JSON.stringify(otherSize)); + }); + + it('test_prebid_indexAdapter_size_sameWidth: same width for all sizes in a slot -> ad server request only for supported sizes', function () { + var valid1Size = [300, 250]; + var otherSize = [300, 999]; + var valid2Size = [300, 600]; + + var configuredBids = [ + IndexUtils.createBidSlot(IndexUtils.DefaultPlacementCodePrefix, 'slot_1', [ valid1Size, otherSize, valid2Size ]) + ]; + adapter.callBids({ bids: configuredBids }); + + assert.isTrue(adLoader.loadScript.called, 'loadScript get request'); + assert.include(adLoader.loadScript.firstCall.args[0], HeaderTagRequest, 'request is headertag request'); + + var requestJSON = IndexUtils.parseIndexRequest(adLoader.loadScript.firstCall.args[0]); + assert.isNotNull(requestJSON.r.imp, 'headertag request include impression object'); + + var impressionObj = requestJSON.r.imp; + + var expandedBids = configuredBids.map(bid => IndexUtils.expandSizes(bid)); + var sidMatched = IndexUtils.matchBidsOnSize(expandedBids, impressionObj); + + for (var i = 0; i < sidMatched.matched.length; i++) { + var pair = sidMatched.matched[i]; + + assert.equal(pair.sent.banner.w, pair.configured.size[0], 'request ' + pair.name + ' width is set to ' + pair.configured.size[0]); + assert.equal(pair.sent.banner.h, pair.configured.size[1], 'request ' + pair.name + ' width is set to ' + pair.configured.size[1]); + assert.equal(pair.sent.ext.siteID, pair.configured.params.siteID, 'request ' + pair.name + ' siteID is set to ' + pair.configured.params.siteID); + } + + assert.equal(sidMatched.unmatched.sent.length, 0, 'All bids in impression object are from configured bids'); + assert.equal(sidMatched.unmatched.configured.length, 1, '1 configured bid is not in impression Obj'); + assert.equal(sidMatched.unmatched.configured[0].size, otherSize, 'configured bid not in impression obj size width is' + JSON.stringify(otherSize)); + }); + + it('test_prebid_indexAdapter_size_sameHeight: same height for all sizes in a slot -> ad server request only for supported sizes', function () { + var valid1Size = [120, 600]; + var otherSize = [999, 600]; + var valid2Size = [300, 600]; + + var configuredBids = [ + IndexUtils.createBidSlot(IndexUtils.DefaultPlacementCodePrefix, 'slot_1', [ valid1Size, otherSize, valid2Size ]) + ]; + adapter.callBids({ bids: configuredBids }); + + assert.isTrue(adLoader.loadScript.called, 'loadScript get request'); + assert.include(adLoader.loadScript.firstCall.args[0], HeaderTagRequest, 'request is headertag request'); + + var requestJSON = IndexUtils.parseIndexRequest(adLoader.loadScript.firstCall.args[0]); + assert.isNotNull(requestJSON.r.imp, 'headertag request include impression object'); + + var impressionObj = requestJSON.r.imp; + + var expandedBids = configuredBids.map(bid => IndexUtils.expandSizes(bid)); + var sidMatched = IndexUtils.matchBidsOnSize(expandedBids, impressionObj); + + for (var i = 0; i < sidMatched.matched.length; i++) { + var pair = sidMatched.matched[i]; + + assert.equal(pair.sent.banner.w, pair.configured.size[0], 'request ' + pair.name + ' width is set to ' + pair.configured.size[0]); + assert.equal(pair.sent.banner.h, pair.configured.size[1], 'request ' + pair.name + ' width is set to ' + pair.configured.size[1]); + assert.equal(pair.sent.ext.siteID, pair.configured.params.siteID, 'request ' + pair.name + ' siteID is set to ' + pair.configured.params.siteID); + } + + assert.equal(sidMatched.unmatched.sent.length, 0, 'All bids in impression object are from configured bids'); + assert.equal(sidMatched.unmatched.configured.length, 1, '1 configured bid is not in impression Obj'); + assert.equal(sidMatched.unmatched.configured[0].size, otherSize, 'configured bid not in impression obj size width is' + JSON.stringify(otherSize)); + }); + + it('test_prebid_indexAdapter_request_sizeID_validation_1: multiple prebid size slot, index slots with size for all prebid slots, 1 slot is not configured properly -> all size in AS request, except misconfigured slot', function () { + var slotID_1 = 52; + var slotID_2 = 53; + var slotSizes_1 = IndexUtils.supportedSizes[0]; + var slotSizes_2 = IndexUtils.supportedSizes[1]; + + var configuredBids = [ + IndexUtils.createBidSlot(IndexUtils.DefaultPlacementCodePrefix, slotID_1, [ slotSizes_1, slotSizes_2 ], { slotSize: [ 728, 'invalid' ] }), + IndexUtils.createBidSlot(IndexUtils.DefaultPlacementCodePrefix, slotID_2, [ slotSizes_1, slotSizes_2 ], { slotSize: slotSizes_2 }) + ]; + + adapter.callBids({ bids: configuredBids }); + + assert.isTrue(adLoader.loadScript.called, 'loadScript get request'); + + assert.include(adLoader.loadScript.firstCall.args[0], HeaderTagRequest, 'request is headertag request'); + + var requestJSON = IndexUtils.parseIndexRequest(adLoader.loadScript.firstCall.args[0]); + assert.isNotNull(requestJSON.r.imp, 'headertag request include impression object'); + + var impressionObj = requestJSON.r.imp; + assert.equal(impressionObj.length, 1, '1 slot is made in the request'); + + assert.equal(impressionObj[0].banner.w, slotSizes_2[0], 'the width made in the request matches with request: ' + slotSizes_2[0]); + assert.equal(impressionObj[0].banner.h, slotSizes_2[1], 'the height made in the request matches with request: ' + slotSizes_2[1]); + assert.equal(impressionObj[0].ext.sid, slotID_2, 'slotID in the request matches with configuration: ' + slotID_2); + assert.equal(impressionObj[0].ext.siteID, IndexUtils.DefaultSiteID, 'siteID in the request matches with request: ' + IndexUtils.DefaultSiteID); + }); +}); diff --git a/test/spec/adapters/inneractive_spec.js b/test/spec/modules/inneractiveBidAdapter_spec.js similarity index 65% rename from test/spec/adapters/inneractive_spec.js rename to test/spec/modules/inneractiveBidAdapter_spec.js index 819e01b0139..8c543c5dba7 100644 --- a/test/spec/adapters/inneractive_spec.js +++ b/test/spec/modules/inneractiveBidAdapter_spec.js @@ -1,10 +1,9 @@ /* globals context */ import {expect} from 'chai'; -import {default as InneractiveAdapter} from 'src/adapters/inneractive'; +import {default as InneractiveAdapter} from 'modules/inneractiveBidAdapter'; import bidmanager from 'src/bidmanager'; - // Using plain-old-style functions, why? see: http://mochajs.org/#arrow-functions describe('InneractiveAdapter', function () { let adapter, @@ -13,60 +12,60 @@ describe('InneractiveAdapter', function () { beforeEach(function () { adapter = InneractiveAdapter.createNew(); bidRequest = { - bidderCode: "inneractive", + bidderCode: 'inneractive', bids: [ { - bidder: "inneractive", + bidder: 'inneractive', params: { - appId: "", + appId: '', }, - placementCode: "div-gpt-ad-1460505748561-0", + placementCode: 'div-gpt-ad-1460505748561-0', sizes: [[300, 250], [300, 600]], - bidId: "507e8db167d219", - bidderRequestId: "49acc957f92917", - requestId: "51381cd0-c29c-405b-9145-20f60abb1e76" + bidId: '507e8db167d219', + bidderRequestId: '49acc957f92917', + requestId: '51381cd0-c29c-405b-9145-20f60abb1e76' }, { - bidder: "inneractive", + bidder: 'inneractive', params: { - noappId: "...", + noappId: '...', }, - placementCode: "div-gpt-ad-1460505661639-0", + placementCode: 'div-gpt-ad-1460505661639-0', sizes: [[728, 90], [970, 90]], - bidId: "507e8db167d220", - bidderRequestId: "49acc957f92917", - requestId: "51381cd0-c29c-405b-9145-20f60abb1e76" + bidId: '507e8db167d220', + bidderRequestId: '49acc957f92917', + requestId: '51381cd0-c29c-405b-9145-20f60abb1e76' }, { - bidder: "inneractive", + bidder: 'inneractive', params: { - APP_ID: "Inneractive_AndroidHelloWorld_Android", - spotType: "rectangle", + APP_ID: 'Inneractive_AndroidHelloWorld_Android', + spotType: 'rectangle', customParams: { Portal: 7002, } }, - placementCode: "div-gpt-ad-1460505748561-0", + placementCode: 'div-gpt-ad-1460505748561-0', sizes: [[320, 50], [300, 600]], - bidId: "507e8db167d221", - bidderRequestId: "49acc957f92917", - requestId: "51381cd0-c29c-405b-9145-20f60abb1e76" + bidId: '507e8db167d221', + bidderRequestId: '49acc957f92917', + requestId: '51381cd0-c29c-405b-9145-20f60abb1e76' }, { - bidder: "inneractive", + bidder: 'inneractive', params: { - appId: "Inneractive_IosHelloWorld_iPhone", - spotType: "banner", // Just for coverage considerations, no real impact in production + appId: 'Inneractive_IosHelloWorld_iPhone', + spotType: 'banner', // Just for coverage considerations, no real impact in production customParams: { portal: 7001, gender: '' } }, - placementCode: "div-gpt-ad-1460505661639-0", + placementCode: 'div-gpt-ad-1460505661639-0', sizes: [[728, 90], [970, 90]], - bidId: "507e8db167d222", - bidderRequestId: "49acc957f92917", - requestId: "51381cd0-c29c-405b-9145-20f60abb1e76" + bidId: '507e8db167d222', + bidderRequestId: '49acc957f92917', + requestId: '51381cd0-c29c-405b-9145-20f60abb1e76' }] }; }); @@ -76,9 +75,9 @@ describe('InneractiveAdapter', function () { it('should contain "mbwError" the inside event report url', function () { const Reporter = InneractiveAdapter._getUtils().Reporter; const extraDetailsParam = { - "appId": "CrunchMind_DailyDisclosure_other", - "spotType": "rectangle", - "portal": 7002 + 'appId': 'CrunchMind_DailyDisclosure_other', + 'spotType': 'rectangle', + 'portal': 7002 }; let eventReportUrl = Reporter.getEventUrl('HBPreBidError', extraDetailsParam); expect(eventReportUrl).to.include('mbwError'); @@ -89,9 +88,9 @@ describe('InneractiveAdapter', function () { describe('.createNew()', function () { it('should return an instance of this adapter having a "callBids" method', function () { expect(adapter) - .to.be.instanceOf(InneractiveAdapter).and - .to.have.property('callBids').and - .to.be.a('function'); + .to.be.instanceOf(InneractiveAdapter).and + .to.have.property('callBids').and + .to.be.a('function'); }); }); @@ -115,15 +114,15 @@ describe('InneractiveAdapter', function () { it('should not issue a request', function () { const Reporter = InneractiveAdapter._getUtils().Reporter; Reporter.getEventUrl('HBPreBidError', { - "appId": "CrunchMind_DailyDisclosure_other", - "spotType": "rectangle", - "portal": 7002 + 'appId': 'CrunchMind_DailyDisclosure_other', + 'spotType': 'rectangle', + 'portal': 7002 }); delete bidRequest.bids; adapter.callBids(bidRequest); - expect(bidRequests).to.be.empty; // jshint ignore:line + expect(bidRequests).to.be.empty; }); }); @@ -133,9 +132,8 @@ describe('InneractiveAdapter', function () { sinon.spy(adapter, '_isValidRequest'); adapter.callBids(bidRequest); - for (let id = 0; id < INVALID_BIDS_COUNT; id++) { - expect(adapter._isValidRequest.getCall(id).returned(false)).to.be.true; // jshint ignore:line + expect(adapter._isValidRequest.getCall(id).returned(false)).to.be.true; } adapter._isValidRequest.restore(); @@ -175,30 +173,30 @@ describe('InneractiveAdapter', function () { beforeEach(function () { adServerResponse = { headers: { - "X-IA-Ad-Height": 250, - "X-IA-Ad-Width": 300, - "X-IA-Error": "OK", - "X-IA-Pricing": "CPM", - "X-IA-Pricing-Currency": "USD", - "X-IA-Pricing-Value": 0.0005 + 'X-IA-Ad-Height': 250, + 'X-IA-Ad-Width': 300, + 'X-IA-Error': 'OK', + 'X-IA-Pricing': 'CPM', + 'X-IA-Pricing-Currency': 'USD', + 'X-IA-Pricing-Value': 0.0005 }, body: { ad: { - html: "
" + html: '' }, config: { tracking: { impressions: [ - "http://event.inner-active.mobi/simpleM2M/reportEvent?eventArchetype=impress…pe=3&network=Inneractive_CS&acp=&pcp=&secure=false&rtb=false&houseAd=false" + 'http://event.inner-active.mobi/simpleM2M/reportEvent?eventArchetype=impress…pe=3&network=Inneractive_CS&acp=&pcp=&secure=false&rtb=false&houseAd=false' ], clicks: [ - "http://event.inner-active.mobi/simpleM2M/reportEvent?eventArchetype=richMed…pe=3&network=Inneractive_CS&acp=&pcp=&secure=false&rtb=false&houseAd=false", - "" + 'http://event.inner-active.mobi/simpleM2M/reportEvent?eventArchetype=richMed…pe=3&network=Inneractive_CS&acp=&pcp=&secure=false&rtb=false&houseAd=false', + '' ], - passback: "http://event.inner-active.mobi/simpleM2M/reportEvent?eventArchetype=passbac…pe=3&network=Inneractive_CS&acp=&pcp=&secure=false&rtb=false&houseAd=false" + passback: 'http://event.inner-active.mobi/simpleM2M/reportEvent?eventArchetype=passbac…pe=3&network=Inneractive_CS&acp=&pcp=&secure=false&rtb=false&houseAd=false' }, moat: { - countryCode: "IL" + countryCode: 'IL' } } } @@ -214,7 +212,7 @@ describe('InneractiveAdapter', function () { let firstRegisteredBidResponse = bidmanager.addBidResponse.firstCall.args[BID_DETAILS_ARG_INDEX]; expect(firstRegisteredBidResponse) - .to.have.property('statusMessage', 'Bid available'); + .to.have.property('statusMessage', 'Bid available'); }); it('should use the first element inside the bid request size array when no (width,height) is returned within the headers', function () { @@ -238,20 +236,20 @@ describe('InneractiveAdapter', function () { beforeEach(function () { passbackAdServerResponse = { headers: { - "X-IA-Error": "House Ad", - "X-IA-Content": 600145, - "X-IA-Cid": 99999, - "X-IA-Publisher": 206536, - "Content-Type": "application/json; charset=UTF-8", - "X-IA-Session": 6512147119979250840, - "X-IA-AdNetwork": "inneractive360" + 'X-IA-Error': 'House Ad', + 'X-IA-Content': 600145, + 'X-IA-Cid': 99999, + 'X-IA-Publisher': 206536, + 'Content-Type': 'application/json; charset=UTF-8', + 'X-IA-Session': 6512147119979250840, + 'X-IA-AdNetwork': 'inneractive360' }, body: { - "ad": { - "html": "" + 'ad': { + 'html': '' }, - "config": { - "passback": "http://event.inner-active.mobi/simpleM2M/reportEvent?eventArchetype=passbac…pe=3&network=Inneractive_CS&acp=&pcp=&secure=false&rtb=false&houseAd=false" + 'config': { + 'passback': 'http://event.inner-active.mobi/simpleM2M/reportEvent?eventArchetype=passbac…pe=3&network=Inneractive_CS&acp=&pcp=&secure=false&rtb=false&houseAd=false' } } }; @@ -266,19 +264,19 @@ describe('InneractiveAdapter', function () { let firstRegisteredBidResponse = bidmanager.addBidResponse.firstCall.args[BID_DETAILS_ARG_INDEX]; expect(firstRegisteredBidResponse) - .to.have.property('statusMessage', 'Bid returned empty or error response'); + .to.have.property('statusMessage', 'Bid returned empty or error response'); }); it('should handle responses from our server in case we had no ad to offer', function () { const n = bidRequest.bids.length; - bidRequest.bids[n - 1].params.appId = "Komoona_InquisitrRectangle2_other"; + bidRequest.bids[n - 1].params.appId = 'Komoona_InquisitrRectangle2_other'; server.respondWith([200, headers, body]); adapter.callBids(bidRequest); server.respond(); let secondRegisteredBidResponse = bidmanager.addBidResponse.secondCall.args[BID_DETAILS_ARG_INDEX]; expect(secondRegisteredBidResponse) - .to.have.property('statusMessage', 'Bid returned empty or error response'); + .to.have.property('statusMessage', 'Bid returned empty or error response'); }); it('should handle JSON.parse errors', function () { @@ -288,7 +286,7 @@ describe('InneractiveAdapter', function () { const firstRegisteredBidResponse = bidmanager.addBidResponse.firstCall.args[BID_DETAILS_ARG_INDEX]; expect(firstRegisteredBidResponse) - .to.have.property('statusMessage', 'Bid returned empty or error response'); + .to.have.property('statusMessage', 'Bid returned empty or error response'); }); }); }); diff --git a/test/spec/modules/innityBidAdapter_spec.js b/test/spec/modules/innityBidAdapter_spec.js new file mode 100644 index 00000000000..7e4ac147c68 --- /dev/null +++ b/test/spec/modules/innityBidAdapter_spec.js @@ -0,0 +1,157 @@ +describe('innity adapter tests', function () { + var expect = require('chai').expect; + var urlParse = require('url-parse'); + var querystringify = require('querystringify'); + var adapter = require('modules/innityBidAdapter'); + var adLoader = require('src/adloader'); + var bidmanager = require('src/bidmanager'); + + var stubLoadScript; + + beforeEach(function () { + stubLoadScript = sinon.stub(adLoader, 'loadScript'); + }); + + afterEach(function () { + stubLoadScript.restore(); + }); + + describe('creation of bid url', function () { + if (typeof ($$PREBID_GLOBAL$$._bidsReceived) === 'undefined') { + $$PREBID_GLOBAL$$._bidsReceived = []; + } + if (typeof ($$PREBID_GLOBAL$$._bidsRequested) === 'undefined') { + $$PREBID_GLOBAL$$._bidsRequested = []; + } + + it('bid request for single placement', function () { + var params = { + bids: [{ + placementCode: '/19968336/header-bid-tag-0', + sizes: [[300, 250]], + bidId: 'b12345', + bidder: 'innity', + params: { pub: '267', zone: '62546' } + }] + }; + + adapter().callBids(params); + + var bidUrl = stubLoadScript.getCall(0).args[0]; + + sinon.assert.calledOnce(stubLoadScript); + + var parsedBidUrl = urlParse(bidUrl); + var parsedBidUrlQueryString = querystringify.parse(parsedBidUrl.query); + + expect(parsedBidUrlQueryString).to.have.property('pub').and.to.equal('267'); + expect(parsedBidUrlQueryString).to.have.property('zone').and.to.equal('62546'); + expect(parsedBidUrlQueryString).to.have.property('width').and.to.equal('300'); + expect(parsedBidUrlQueryString).to.have.property('height').and.to.equal('250'); + }); + }); + + describe('handling bid response', function () { + it('should return complete bid response', function() { + var stubAddBidResponse = sinon.stub(bidmanager, 'addBidResponse'); + + var params = { + bids: [{ + placementCode: '/19968336/header-bid-tag-0', + sizes: [[300, 250]], + bidId: 'b12345', + bidder: 'innity', + params: { pub: '267', zone: '62546' } + }] + }; + + var response = { + cpm: 100, + width: 300, + height: 250, + callback_uid: 'b12345', + tag: '" + 'placementid': 'abcd123123dcba', + 'uuid': '30e5e911c00703', + 'width': 728, + 'height': 90, + 'cpm': 0.5, + 'creative': '' } ] }; describe('komoonaAdapter', () => { - let adapter; beforeEach(() => adapter = Adapter.createNew()); describe('request function', () => { - let xhr; let requests; let pbConfig; @@ -58,7 +55,7 @@ describe('komoonaAdapter', () => { requests = []; xhr.onCreate = request => requests.push(request); pbConfig = REQUEST; - //just a single slot + // just a single slot pbConfig.bids = [pbConfig.bids[0]]; }); @@ -75,11 +72,11 @@ describe('komoonaAdapter', () => { it('requires placementid and hbid', () => { let backup = pbConfig.bids[0].params; - pbConfig.bids[0].params = {placementid : 1234}; //no hbid + pbConfig.bids[0].params = {placementid: 1234}; // no hbid adapter.callBids(pbConfig); expect(requests).to.be.empty; - pbConfig.bids[0].params = {hbid : 1234}; //no placementid + pbConfig.bids[0].params = {hbid: 1234}; // no placementid adapter.callBids(pbConfig); expect(requests).to.be.empty; @@ -94,7 +91,6 @@ describe('komoonaAdapter', () => { }); describe('response handler', () => { - let server; beforeEach(() => { @@ -121,10 +117,10 @@ describe('komoonaAdapter', () => { it('handles nobid responses', () => { server.respondWith(JSON.stringify({ - "bids": [{ - "cpm": 0, - "creative": "", - "uuid": "30e5e911c00703" + 'bids': [{ + 'cpm': 0, + 'creative': '', + 'uuid': '30e5e911c00703' }] })); @@ -152,7 +148,5 @@ describe('komoonaAdapter', () => { 'Bid returned empty or error response' ); }); - }); - }); diff --git a/test/spec/adapters/lifestreet_spec.js b/test/spec/modules/lifestreetBidAdapter_spec.js similarity index 98% rename from test/spec/adapters/lifestreet_spec.js rename to test/spec/modules/lifestreetBidAdapter_spec.js index 848c899fcbf..bb93ad90ef2 100644 --- a/test/spec/adapters/lifestreet_spec.js +++ b/test/spec/modules/lifestreetBidAdapter_spec.js @@ -2,7 +2,7 @@ import {expect} from 'chai'; import {cloneJson} from 'src/utils'; import adloader from 'src/adloader'; import bidmanager from 'src/bidmanager'; -import LifestreetAdapter from 'src/adapters/lifestreet'; +import LifestreetAdapter from 'modules/lifestreetBidAdapter'; const BIDDER_REQUEST = { auctionStart: new Date().getTime(), @@ -28,7 +28,7 @@ const BIDDER_REQUEST = { timeout: 3000 }; -describe ('LifestreetAdapter', () => { +describe('LifestreetAdapter', () => { let adapter; beforeEach(() => adapter = new LifestreetAdapter()); @@ -100,7 +100,7 @@ describe ('LifestreetAdapter', () => { expect(tagRequests).to.be.empty; }); - it ('adkey is not provided', () => { + it('adkey is not provided', () => { request.bids[0].params.adkey = ''; adapter.callBids(request); expect(tagRequests).to.be.empty; @@ -228,4 +228,4 @@ describe ('LifestreetAdapter', () => { }); }); }); -}); \ No newline at end of file +}); diff --git a/test/spec/modules/mantisBidAdapter_spec.js b/test/spec/modules/mantisBidAdapter_spec.js new file mode 100644 index 00000000000..e417ea51c04 --- /dev/null +++ b/test/spec/modules/mantisBidAdapter_spec.js @@ -0,0 +1,168 @@ +'use strict'; + +describe('mantis adapter tests', function () { + const expect = require('chai').expect; + const adapter = require('modules/mantisBidAdapter'); + const bidmanager = require('src/bidmanager'); + const adloader = require('src/adloader'); + const constants = require('src/constants.json'); + + var mantis, sandbox; + + beforeEach(() => { + mantis = new adapter(); + sandbox = sinon.sandbox.create(); + }); + + afterEach(() => { + sandbox.restore(); + + delete window.context; + delete window.mantis_link; + delete window.mantis_breakpoint; + delete window.mantis_uuid; + }); + + var callBidExample = { + bidderCode: 'mantis', + bids: [ + { + bidId: 'bidId1', + bidder: 'mantis', + placementCode: 'foo', + sizes: [[728, 90]], + params: { + property: '1234', + zoneId: 'zone1' + } + }, + { + bidId: 'bidId2', + bidder: 'mantis', + placementCode: 'bar', + sizes: [[300, 600], [300, 250]], + params: { + property: '1234', + zoneId: 'zone2' + } + } + ] + }; + + describe('callBids', () => { + it('should create appropriate bid responses', () => { + sandbox.stub(bidmanager, 'addBidResponse'); + sandbox.stub(adloader, 'loadScript', function (url) { + var jsonp = eval(decodeURIComponent(url.match(/jsonp=(.*)&property/)[1])); + + jsonp({ + ads: { + bidId1: { + cpm: 1, + html: '', + width: 300, + height: 600 + } + } + }); + }); + + mantis.callBids(callBidExample); + + sinon.assert.calledTwice(bidmanager.addBidResponse); + + expect(bidmanager.addBidResponse.firstCall.args[0]).to.eql('foo'); + + var bid1 = bidmanager.addBidResponse.firstCall.args[1]; + expect(bid1.getStatusCode()).to.eql(constants.STATUS.GOOD); + expect(bid1.bidderCode).to.eql('mantis'); + expect(bid1.cpm).to.eql(1); + expect(bid1.ad).to.eql(''); + expect(bid1.width).to.eql(300); + expect(bid1.height).to.eql(600); + + expect(bidmanager.addBidResponse.secondCall.args[0]).to.eql('bar'); + + var bid2 = bidmanager.addBidResponse.secondCall.args[1]; + expect(bid2.getStatusCode()).to.eql(constants.STATUS.NO_BID); + expect(bid2.bidderCode).to.eql('mantis'); + }); + + it('should load script with relevant bid data', () => { + sandbox.stub(adloader, 'loadScript'); + + mantis.callBids(callBidExample); + + sinon.assert.calledOnce(adloader.loadScript); + + var serverCall = adloader.loadScript.firstCall.args[0]; + + expect(serverCall).to.match(/buster=[0-9]+&/); + expect(serverCall).to.match(/tz=-?[0-9]+&/); + expect(serverCall).to.match(/secure=(true|false)&/); + expect(serverCall).to.string('property=1234&'); + expect(serverCall).to.string('bids[0][bidId]=bidId1&'); + expect(serverCall).to.string('bids[0][sizes][0][width]=728&'); + expect(serverCall).to.string('bids[0][sizes][0][height]=90&'); + expect(serverCall).to.string('bids[0][config][zoneId]=zone1&'); + expect(serverCall).to.string('bids[1][bidId]=bidId2&'); + expect(serverCall).to.string('bids[1][sizes][0][width]=300&'); + expect(serverCall).to.string('bids[1][sizes][0][height]=600&'); + expect(serverCall).to.string('bids[1][sizes][1][width]=300&'); + expect(serverCall).to.string('bids[1][sizes][1][height]=250&'); + expect(serverCall).to.string('bids[1][config][zoneId]=zone2&'); + expect(serverCall).to.string('version=1'); + }); + + /* tests below are to just adhere to code coverage requirements, but it is already tested in our own libraries/deployment process */ + it('should send uuid from window if set', () => { + sandbox.stub(adloader, 'loadScript'); + + window.mantis_uuid = '4321'; + + mantis.callBids(callBidExample); + + sinon.assert.calledOnce(adloader.loadScript); + + var serverCall = adloader.loadScript.firstCall.args[0]; + + expect(serverCall).to.string('uuid=4321&'); + }); + + it('should send mobile = true if breakpoint is hit', () => { + sandbox.stub(adloader, 'loadScript'); + + window.mantis_link = true; // causes iframe detection to not work + window.mantis_breakpoint = 100000000; // force everything to be mobile + + mantis.callBids(callBidExample); + + sinon.assert.calledOnce(adloader.loadScript); + + var serverCall = adloader.loadScript.firstCall.args[0]; + + expect(serverCall).to.string('mobile=true&'); + }); + + it('should send different params if amp is detected', () => { + sandbox.stub(adloader, 'loadScript'); + + window.context = { + tagName: 'AMP-AD', + location: { + href: 'bar', + referrer: 'baz' + } + }; + + mantis.callBids(callBidExample); + + sinon.assert.calledOnce(adloader.loadScript); + + var serverCall = adloader.loadScript.firstCall.args[0]; + + expect(serverCall).to.string('mobile=true&'); + // expect(serverCall).to.string('url=bar&'); + }); + }); +}); diff --git a/test/spec/adapters/memeglobal_spec.js b/test/spec/modules/memeglobalBidAdapter_spec.js similarity index 62% rename from test/spec/adapters/memeglobal_spec.js rename to test/spec/modules/memeglobalBidAdapter_spec.js index 278d7986000..0dc2d6f1541 100644 --- a/test/spec/adapters/memeglobal_spec.js +++ b/test/spec/modules/memeglobalBidAdapter_spec.js @@ -1,26 +1,26 @@ describe('memeglobal adapter tests', function () { const expect = require('chai').expect; - const adapter = require('src/adapters/memeglobal'); + const adapter = require('modules/memeglobalBidAdapter'); const bidmanager = require('src/bidmanager'); const adLoader = require('src/adloader'); var bidderName = 'memeglobal'; let stubLoadScript; - beforeEach(function () { - stubLoadScript = sinon.stub(adLoader, 'loadScript'); - }); + beforeEach(function () { + stubLoadScript = sinon.stub(adLoader, 'loadScript'); + }); - afterEach(function () { - stubLoadScript.restore(); - }); + afterEach(function () { + stubLoadScript.restore(); + }); function getBidSetForBidder() { - return pbjs._bidsRequested.find(bidSet => bidSet.bidderCode === bidderName); + return $$PREBID_GLOBAL$$._bidsRequested.find(bidSet => bidSet.bidderCode === bidderName); } function checkBidsRequestedInit() { var bidSet = getBidSetForBidder(); - if (!bidSet){ + if (!bidSet) { var bidderRequest = { start: null, requestId: null, @@ -28,28 +28,28 @@ describe('memeglobal adapter tests', function () { bidderCode: 'memeglobal', bids: [] }; - pbjs._bidsRequested.push(bidderRequest); + $$PREBID_GLOBAL$$._bidsRequested.push(bidderRequest); } } describe('functions and initialization', function () { it('should exist and be a function', function () { - expect(pbjs.mgres).to.exist.and.to.be.a('function'); + expect($$PREBID_GLOBAL$$.mgres).to.exist.and.to.be.a('function'); }); it('callBids with params', function () { var params = { - bidderCode: 'memeglobal', + bidderCode: 'memeglobal', + bidder: 'memeglobal', + bids: [{ + bidId: '3c9408cdbf2f68', + sizes: [[300, 250]], bidder: 'memeglobal', - bids: [{ - bidId: '3c9408cdbf2f68', - sizes: [[300, 250]], - bidder: 'memeglobal', - params: { siteId: '3608', adSizes:'300x250' }, - requestId: '10b327aa396609', - placementCode: 'header-bid-tag-0' - } - ] + params: { siteId: '3608', adSizes: '300x250' }, + requestId: '10b327aa396609', + placementCode: 'header-bid-tag-0' + } + ] }; adapter().callBids(params); @@ -58,17 +58,17 @@ describe('memeglobal adapter tests', function () { it('callBids empty params', function () { var params = { - bidderCode: 'memeglobal', + bidderCode: 'memeglobal', + bidder: 'memeglobal', + bids: [{ + bidId: '3c9408cdbf2f68', + sizes: [[300, 250]], bidder: 'memeglobal', - bids: [{ - bidId: '3c9408cdbf2f68', - sizes: [[300, 250]], - bidder: 'memeglobal', - params: { siteId: '3608', adSizes:'300x250' }, - requestId: '10b327aa396609', - placementCode: 'header-bid-tag-0' - } - ] + params: { siteId: '3608', adSizes: '300x250' }, + requestId: '10b327aa396609', + placementCode: 'header-bid-tag-0' + } + ] }; adapter().callBids({}); @@ -88,12 +88,12 @@ describe('memeglobal adapter tests', function () { tagid: '007' }, sizes: [[300, 250]], - placementCode: "test-1" + placementCode: 'test-1' } // no bids returned in the response. var response = { - "id": "54321", - "seatbid": [] + 'id': '54321', + 'seatbid': [] }; var bidSet = getBidSetForBidder(); bidSet.bids.push(bid); @@ -101,15 +101,15 @@ describe('memeglobal adapter tests', function () { // adapter needs to be called for stub registration. adapter() - pbjs.mgres(response); + $$PREBID_GLOBAL$$.mgres(response); expect(stubAddBidResponse.getCall(0)).to.equal(null); -// var bidPlacementCode = stubAddBidResponse.getCall(0).args[0]; -// expect(bidPlacementCode).to.equal('test-1'); -// -// var bidObject1 = stubAddBidResponse.getCall(0).args[1]; -// expect(bidObject1.getStatusCode()).to.equal(2); -// expect(bidObject1.bidderCode).to.equal('memeglobal'); + // var bidPlacementCode = stubAddBidResponse.getCall(0).args[0]; + // expect(bidPlacementCode).to.equal('test-1'); + // + // var bidObject1 = stubAddBidResponse.getCall(0).args[1]; + // expect(bidObject1.getStatusCode()).to.equal(2); + // expect(bidObject1.bidderCode).to.equal('memeglobal'); stubAddBidResponse.calledThrice; stubAddBidResponse.restore(); @@ -131,26 +131,25 @@ describe('memeglobal adapter tests', function () { // Returning a single bid in the response. var response = { - "id": "54321111", - "seatbid": [ { - "bid" : [ { - "id" : "1111111", - "impid" : "bidId2", - "price" : 0.09, - "nurl" : "http://url", - "adm" : "ad-code", - "h" : 250, - "w" : 300, - "ext" : { } + 'id': '54321111', + 'seatbid': [ { + 'bid': [ { + 'id': '1111111', + 'impid': 'bidId2', + 'price': 0.09, + 'nurl': 'http://url', + 'adm': 'ad-code', + 'h': 250, + 'w': 300, + 'ext': { } } ] } ] }; - var bidSet = getBidSetForBidder(); bidSet.bids.push(bid); adapter() - pbjs.mgres(response); + $$PREBID_GLOBAL$$.mgres(response); var bidPlacementCode1 = stubAddBidResponse.getCall(0).args[0]; var bidObject1 = stubAddBidResponse.getCall(0).args[1]; diff --git a/test/spec/adapters/openx_spec.js b/test/spec/modules/openxBidAdapter_spec.js similarity index 72% rename from test/spec/adapters/openx_spec.js rename to test/spec/modules/openxBidAdapter_spec.js index 50d71064da7..c828aacda6a 100644 --- a/test/spec/adapters/openx_spec.js +++ b/test/spec/modules/openxBidAdapter_spec.js @@ -1,8 +1,7 @@ describe('openx adapter tests', function () { - const expect = require('chai').expect; const assert = require('chai').assert; - const adapter = require('src/adapters/openx'); + const adapter = require('modules/openxBidAdapter'); const bidmanager = require('src/bidmanager'); const adloader = require('src/adloader'); const CONSTANTS = require('src/constants.json'); @@ -11,9 +10,8 @@ describe('openx adapter tests', function () { after(() => document.body.appendChild.restore()); describe('test openx callback responce', function () { - it('should exist and be a function', function () { - expect(pbjs.oxARJResponse).to.exist.and.to.be.a('function'); + expect($$PREBID_GLOBAL$$.oxARJResponse).to.exist.and.to.be.a('function'); }); it('should add empty bid responses if no bids returned', function () { @@ -37,20 +35,20 @@ describe('openx adapter tests', function () { // empty ads in bidresponse let response = { - "ads": + 'ads': { - "version": 1, - "count": 1, - "pixels": "http://testpixels.net", - "ad": [] + 'version': 1, + 'count': 1, + 'pixels': 'http://testpixels.net', + 'ad': [] } }; - pbjs._bidsRequested.push(bidderRequest); + $$PREBID_GLOBAL$$._bidsRequested.push(bidderRequest); // adapter needs to be called, in order for the stub to register. adapter(); - pbjs.oxARJResponse(response); + $$PREBID_GLOBAL$$.oxARJResponse(response); let bidPlacementCode1 = stubAddBidResponse.getCall(0).args[0]; let bidResponse1 = stubAddBidResponse.getCall(0).args[1]; @@ -82,35 +80,35 @@ describe('openx adapter tests', function () { // empty ads in bidresponse let response = { - "ads": + 'ads': { - "version": 1, - "count": 1, - "pixels": "http://testpixels.net", - "ad": [ + 'version': 1, + 'count': 1, + 'pixels': 'http://testpixels.net', + 'ad': [ { - "adunitid": 1234, - "adid": 5678, - "type": "html", - "html": "test_html", - "framed": 1, - "is_fallback": 0, - "ts": "ts", - "cpipc": 1000, - "pub_rev": "1000", - "adv_id": "adv_id", - "brand_id": "", - "creative": [ + 'adunitid': 1234, + 'adid': 5678, + 'type': 'html', + 'html': 'test_html', + 'framed': 1, + 'is_fallback': 0, + 'ts': 'ts', + 'cpipc': 1000, + 'pub_rev': '1000', + 'adv_id': 'adv_id', + 'brand_id': '', + 'creative': [ { - "width": "300", - "height": "250", - "target": "_blank", - "mime": "text/html", - "media": "test_media", - "tracking": { - "impression": "test_impression", - "inview": "test_inview", - "click": "test_click" + 'width': '300', + 'height': '250', + 'target': '_blank', + 'mime': 'text/html', + 'media': 'test_media', + 'tracking': { + 'impression': 'test_impression', + 'inview': 'test_inview', + 'click': 'test_click' } } ] @@ -118,11 +116,11 @@ describe('openx adapter tests', function () { } }; - pbjs._bidsRequested.push(bidderRequest); + $$PREBID_GLOBAL$$._bidsRequested.push(bidderRequest); // adapter needs to be called, in order for the stub to register. adapter(); - pbjs.oxARJResponse(response); + $$PREBID_GLOBAL$$.oxARJResponse(response); let bidPlacementCode1 = stubAddBidResponse.getCall(0).args[0]; let bidResponse1 = stubAddBidResponse.getCall(0).args[1]; @@ -159,35 +157,35 @@ describe('openx adapter tests', function () { // Empty pub rev in bid response let response = { - "ads": + 'ads': { - "version": 1, - "count": 1, - "pixels": "http://testpixels.net", - "ad": [ + 'version': 1, + 'count': 1, + 'pixels': 'http://testpixels.net', + 'ad': [ { - "adunitid": 1234, - "adid": 5678, - "type": "html", - "html": "test_html", - "framed": 1, - "is_fallback": 1, - "ts": "ts", - "cpipc": 1000, - "pub_rev": "", - "adv_id": "adv_id", - "brand_id": "", - "creative": [ + 'adunitid': 1234, + 'adid': 5678, + 'type': 'html', + 'html': 'test_html', + 'framed': 1, + 'is_fallback': 1, + 'ts': 'ts', + 'cpipc': 1000, + 'pub_rev': '', + 'adv_id': 'adv_id', + 'brand_id': '', + 'creative': [ { - "width": "300", - "height": "250", - "target": "_blank", - "mime": "text/html", - "media": "test_media", - "tracking": { - "impression": "test_impression", - "inview": "test_inview", - "click": "test_click" + 'width': '300', + 'height': '250', + 'target': '_blank', + 'mime': 'text/html', + 'media': 'test_media', + 'tracking': { + 'impression': 'test_impression', + 'inview': 'test_inview', + 'click': 'test_click' } } ] @@ -195,11 +193,11 @@ describe('openx adapter tests', function () { } }; - pbjs._bidsRequested.push(bidderRequest); + $$PREBID_GLOBAL$$._bidsRequested.push(bidderRequest); // adapter needs to be called, in order for the stub to register. adapter(); - pbjs.oxARJResponse(response); + $$PREBID_GLOBAL$$.oxARJResponse(response); let bidPlacementCode1 = stubAddBidResponse.getCall(0).args[0]; let bidResponse1 = stubAddBidResponse.getCall(0).args[1]; @@ -265,5 +263,4 @@ describe('openx adapter tests', function () { expect(bidUrl).to.include('c.test1=testval1'); spyLoadScript.restore(); }); - }); diff --git a/test/spec/modules/piximediaBidAdapter_spec.js b/test/spec/modules/piximediaBidAdapter_spec.js new file mode 100644 index 00000000000..a3b01202102 --- /dev/null +++ b/test/spec/modules/piximediaBidAdapter_spec.js @@ -0,0 +1,416 @@ +describe('Piximedia adapter tests', function () { + var expect = require('chai').expect; + var urlParse = require('url-parse'); + + // var querystringify = require('querystringify'); + + var adapter = require('modules/piximediaBidAdapter'); + var adLoader = require('src/adloader'); + var bidmanager = require('src/bidmanager'); + var utils = require('src/utils'); + var CONSTANTS = require('src/constants.json'); + + let stubLoadScript; + + beforeEach(function () { + stubLoadScript = sinon.stub(adLoader, 'loadScript'); + }); + + afterEach(function () { + stubLoadScript.restore(); + }); + + describe('creation of prebid url', function () { + if (typeof ($$PREBID_GLOBAL$$._bidsReceived) === 'undefined') { + $$PREBID_GLOBAL$$._bidsReceived = []; + } + if (typeof ($$PREBID_GLOBAL$$._bidsRequested) === 'undefined') { + $$PREBID_GLOBAL$$._bidsRequested = []; + } + if (typeof ($$PREBID_GLOBAL$$._adsReceived) === 'undefined') { + $$PREBID_GLOBAL$$._adsReceived = []; + } + + it('should call the Piximedia prebid URL once on valid calls', function () { + var params = { + bidderCode: 'piximedia', + bidder: 'piximedia', + bids: [ + { + bidId: '4d3819cffc4d12', + sizes: [[300, 250]], + bidder: 'piximedia', + params: { siteId: 'TEST', placementId: 'TEST', prebidUrl: '//resources.pm/tests/prebid/bids.js' }, + requestId: '59c318fd382219', + placementCode: '/20164912/header-bid-tag-0' + } + ] + }; + + adapter().callBids(params); + sinon.assert.calledOnce(stubLoadScript); + }); + + it('should not call the Piximedia prebid URL once on invalid calls', function () { + var params = { + bidderCode: 'piximedia', + bidder: 'piximedia', + bids: [ + { + bidId: '4d3819cffc4d12', + sizes: [[300, 250]], + bidder: 'piximedia', + params: { prebidUrl: '//resources.pm/tests/prebid/bids.js' }, // this is invalid: site and placement ID are missing + requestId: '59c318fd382219', + placementCode: '/20164912/header-bid-tag-0' + } + ] + }; + + adapter().callBids(params); + sinon.assert.notCalled(stubLoadScript); + }); + + it('should call the correct Prebid URL when using the default URL', function () { + var params = { + bidderCode: 'piximedia', + bidder: 'piximedia', + bids: [ + { + bidId: '4d3819cffc4d12', + sizes: [[300, 250]], + bidder: 'piximedia', + params: { siteId: 'TEST', placementId: 'TEST' }, + requestId: '59c318fd382219', + placementCode: '/20164912/header-bid-tag-0' + } + ] + }; + + adapter().callBids(params); + var bidUrl = stubLoadScript.getCall(0).args[0]; + + sinon.assert.calledWith(stubLoadScript, bidUrl); + + var parsedBidUrl = urlParse(bidUrl); + + expect(parsedBidUrl.hostname).to.equal('static.adserver.pm'); + expect(parsedBidUrl.query).to.equal(''); + expect(parsedBidUrl.pathname.replace(/cbid=[a-f0-9]+/, 'cbid=210af5668b1e23').replace(/rand=[0-9]+$/, 'rand=42')).to.equal('/prebid/site_id=TEST/placement_id=TEST/jsonp=pbjs.handlePiximediaCallback/sizes=300x250/cbid=210af5668b1e23/rand=42'); + }); + + it('should call the correct Prebid URL when using the default URL with a deal and custom data', function () { + var params = { + bidderCode: 'piximedia', + bidder: 'piximedia', + bids: [ + { + bidId: '4d3819cffc4d12', + sizes: [[300, 250]], + bidder: 'piximedia', + params: { siteId: 'TEST', placementId: 'TEST', dealId: 1295, custom: 'bespoke', custom2: function() { return 'bespoke2'; }, custom3: null, custom4: function() {} }, + requestId: '59c318fd382219', + placementCode: '/20164912/header-bid-tag-0' + } + ] + }; + + adapter().callBids(params); + var bidUrl = stubLoadScript.getCall(0).args[0]; + + sinon.assert.calledWith(stubLoadScript, bidUrl); + + var parsedBidUrl = urlParse(bidUrl); + + expect(parsedBidUrl.hostname).to.equal('static.adserver.pm'); + expect(parsedBidUrl.query).to.equal(''); + expect(parsedBidUrl.pathname.replace(/cbid=[a-f0-9]+/, 'cbid=210af5668b1e23').replace(/rand=[0-9]+$/, 'rand=42')).to.equal('/prebid/site_id=TEST/placement_id=TEST/l_id=1295/custom=bespoke/custom2=bespoke2/custom3=/custom4=/jsonp=$$PREBID_GLOBAL$$.handlePiximediaCallback/sizes=300x250/cbid=210af5668b1e23/rand=42'); + }); + + it('should call the correct Prebid URL when using the default URL and overridding sizes', function () { + var params = { + bidderCode: 'piximedia', + bidder: 'piximedia', + bids: [ + { + bidId: '4d3819cffc4d12', + sizes: [[300, 250]], + bidder: 'piximedia', + params: { siteId: 'TEST', placementId: 'TEST', sizes: [[300, 600], [728, 90]] }, + requestId: '59c318fd382219', + placementCode: '/20164912/header-bid-tag-0' + } + ] + }; + + adapter().callBids(params); + var bidUrl = stubLoadScript.getCall(0).args[0]; + + sinon.assert.calledWith(stubLoadScript, bidUrl); + + var parsedBidUrl = urlParse(bidUrl); + + expect(parsedBidUrl.hostname).to.equal('static.adserver.pm'); + expect(parsedBidUrl.query).to.equal(''); + expect(parsedBidUrl.pathname.replace(/cbid=[a-f0-9]+/, 'cbid=210af5668b1e23').replace(/rand=[0-9]+$/, 'rand=42')).to.equal('/prebid/site_id=TEST/placement_id=TEST/jsonp=$$PREBID_GLOBAL$$.handlePiximediaCallback/sizes=300x600%2C728x90/cbid=210af5668b1e23/rand=42'); + }); + + it('should call the correct Prebid URL when supplying a custom URL', function () { + var params = { + bidderCode: 'piximedia', + bidder: 'piximedia', + bids: [ + { + bidId: '4d3819cffc4d12', + sizes: [[300, 250]], + bidder: 'piximedia', + params: { siteId: 'TEST', placementId: 'TEST', prebidUrl: '//resources.pm/tests/prebid/bids.js' }, + requestId: '59c318fd382219', + placementCode: '/20164912/header-bid-tag-0' + } + ] + }; + + adapter().callBids(params); + var bidUrl = stubLoadScript.getCall(0).args[0]; + + sinon.assert.calledWith(stubLoadScript, bidUrl); + + var parsedBidUrl = urlParse(bidUrl); + + expect(parsedBidUrl.hostname).to.equal('resources.pm'); + expect(parsedBidUrl.query).to.equal(''); + expect(parsedBidUrl.pathname.replace(/cbid=[a-f0-9]+/, 'cbid=210af5668b1e23').replace(/rand=[0-9]+$/, 'rand=42')).to.equal('/tests/prebid/bids.js/site_id=TEST/placement_id=TEST/jsonp=$$PREBID_GLOBAL$$.handlePiximediaCallback/sizes=300x250/cbid=210af5668b1e23/rand=42'); + }); + }); + + describe('handling of the callback response', function () { + if (typeof ($$PREBID_GLOBAL$$._bidsReceived) === 'undefined') { + $$PREBID_GLOBAL$$._bidsReceived = []; + } + if (typeof ($$PREBID_GLOBAL$$._bidsRequested) === 'undefined') { + $$PREBID_GLOBAL$$._bidsRequested = []; + } + if (typeof ($$PREBID_GLOBAL$$._adsReceived) === 'undefined') { + $$PREBID_GLOBAL$$._adsReceived = []; + } + + var params = { + bidderCode: 'piximedia', + bidder: 'piximedia', + bids: [ + { + bidId: '4d3819cffc4d12', + sizes: [[300, 250]], + bidder: 'piximedia', + params: { siteId: 'TEST', placementId: 'TEST', prebidUrl: '//resources.pm/tests/prebid/bids.js' }, + requestId: '59c318fd382219', + placementCode: '/20164912/header-bid-tag-0' + } + ] + }; + + it('Piximedia callback function should exist', function () { + expect($$PREBID_GLOBAL$$.handlePiximediaCallback).to.exist.and.to.be.a('function'); + }); + + it('bidmanager.addBidResponse should be called once with correct arguments', function () { + var stubAddBidResponse = sinon.stub(bidmanager, 'addBidResponse'); + var stubGetUniqueIdentifierStr = sinon.spy(utils, 'getUniqueIdentifierStr'); + + var response = { + foundbypm: true, + currency: 'EUR', + cpm: 1.23, + dealId: 9948, + width: 300, + height: 250, + html: '
ad
' + }; + + adapter().callBids(params); + + var adUnits = []; + var unit = {}; + unit.bids = [params]; + unit.code = '/20164912/header-bid-tag'; + unit.sizes = [[300, 250], [728, 90]]; + adUnits.push(unit); + + if (typeof ($$PREBID_GLOBAL$$._bidsRequested) === 'undefined') { + $$PREBID_GLOBAL$$._bidsRequested = [params]; + } else { + $$PREBID_GLOBAL$$._bidsRequested.push(params); + } + $$PREBID_GLOBAL$$.adUnits = adUnits; + response.cbid = stubGetUniqueIdentifierStr.returnValues[0]; + + $$PREBID_GLOBAL$$.handlePiximediaCallback(response); + + sinon.assert.calledOnce(stubAddBidResponse); + var bidPlacementCode1 = stubAddBidResponse.getCall(0).args[0]; + var bidObject1 = stubAddBidResponse.getCall(0).args[1]; + + expect(bidPlacementCode1).to.equal('/20164912/header-bid-tag-0'); + expect(bidObject1.cpm).to.equal(1.23); + expect(bidObject1.ad).to.equal('
ad
'); + expect(bidObject1.width).to.equal(300); + expect(bidObject1.dealId).to.equal(9948); + expect(bidObject1.height).to.equal(250); + expect(bidObject1.getStatusCode()).to.equal(CONSTANTS.STATUS.GOOD); + expect(bidObject1.bidderCode).to.equal('piximedia'); + + stubAddBidResponse.restore(); + stubGetUniqueIdentifierStr.restore(); + }); + + it('bidmanager.addBidResponse should be called once with correct arguments on partial response', function () { + var stubAddBidResponse = sinon.stub(bidmanager, 'addBidResponse'); + var stubGetUniqueIdentifierStr = sinon.spy(utils, 'getUniqueIdentifierStr'); + + // this time, we do not provide dealId + var response = { + foundbypm: true, + cpm: 1.23, + width: 300, + height: 250, + currency: 'EUR', + html: '
ad
' + }; + + adapter().callBids(params); + + var adUnits = []; + var unit = {}; + unit.bids = [params]; + unit.code = '/20164912/header-bid-tag'; + unit.sizes = [[300, 250], [728, 90]]; + adUnits.push(unit); + + if (typeof ($$PREBID_GLOBAL$$._bidsRequested) === 'undefined') { + $$PREBID_GLOBAL$$._bidsRequested = [params]; + } else { + $$PREBID_GLOBAL$$._bidsRequested.push(params); + } + $$PREBID_GLOBAL$$.adUnits = adUnits; + response.cbid = stubGetUniqueIdentifierStr.returnValues[0]; + + $$PREBID_GLOBAL$$.handlePiximediaCallback(response); + + sinon.assert.calledOnce(stubAddBidResponse); + var bidPlacementCode1 = stubAddBidResponse.getCall(0).args[0]; + var bidObject1 = stubAddBidResponse.getCall(0).args[1]; + + expect(bidPlacementCode1).to.equal('/20164912/header-bid-tag-0'); + expect(bidObject1.cpm).to.equal(1.23); + expect(bidObject1.ad).to.equal('
ad
'); + expect(bidObject1.width).to.equal(300); + expect(bidObject1.height).to.equal(250); + expect(bidObject1.getStatusCode()).to.equal(CONSTANTS.STATUS.GOOD); + expect(bidObject1.bidderCode).to.equal('piximedia'); + + stubAddBidResponse.restore(); + stubGetUniqueIdentifierStr.restore(); + }); + + it('bidmanager.addBidResponse should be called once without any ads', function () { + var stubAddBidResponse = sinon.stub(bidmanager, 'addBidResponse'); + var stubGetUniqueIdentifierStr = sinon.spy(utils, 'getUniqueIdentifierStr'); + + var response = { + foundbypm: false + }; + + adapter().callBids(params); + + var adUnits = []; + var unit = {}; + unit.bids = [params]; + unit.code = '/20164912/header-bid-tag'; + unit.sizes = [[300, 250], [728, 90]]; + adUnits.push(unit); + + if (typeof ($$PREBID_GLOBAL$$._bidsRequested) === 'undefined') { + $$PREBID_GLOBAL$$._bidsRequested = [params]; + } else { + $$PREBID_GLOBAL$$._bidsRequested.push(params); + } + $$PREBID_GLOBAL$$.adUnits = adUnits; + response.cbid = stubGetUniqueIdentifierStr.returnValues[0]; + + $$PREBID_GLOBAL$$.handlePiximediaCallback(response); + + sinon.assert.calledOnce(stubAddBidResponse); + var bidPlacementCode1 = stubAddBidResponse.getCall(0).args[0]; + var bidObject1 = stubAddBidResponse.getCall(0).args[1]; + + expect(bidPlacementCode1).to.equal('/20164912/header-bid-tag-0'); + expect(bidObject1.getStatusCode()).to.equal(CONSTANTS.STATUS.NO_BID); + expect(bidObject1.bidderCode).to.equal('piximedia'); + + stubAddBidResponse.restore(); + stubGetUniqueIdentifierStr.restore(); + }); + + it('bidmanager.addBidResponse should not be called on bogus cbid', function () { + var stubAddBidResponse = sinon.stub(bidmanager, 'addBidResponse'); + var stubGetUniqueIdentifierStr = sinon.spy(utils, 'getUniqueIdentifierStr'); + + var response = { + foundbypm: false + }; + + adapter().callBids(params); + + var adUnits = []; + var unit = {}; + unit.bids = [params]; + unit.code = '/20164912/header-bid-tag'; + unit.sizes = [[300, 250], [728, 90]]; + adUnits.push(unit); + + if (typeof ($$PREBID_GLOBAL$$._bidsRequested) === 'undefined') { + $$PREBID_GLOBAL$$._bidsRequested = [params]; + } else { + $$PREBID_GLOBAL$$._bidsRequested.push(params); + } + $$PREBID_GLOBAL$$.adUnits = adUnits; + response.cbid = stubGetUniqueIdentifierStr.returnValues[0] + '_BOGUS'; + + $$PREBID_GLOBAL$$.handlePiximediaCallback(response); + + sinon.assert.notCalled(stubAddBidResponse); + + stubAddBidResponse.restore(); + stubGetUniqueIdentifierStr.restore(); + }); + + it('bidmanager.addBidResponse should not be called on bogus response', function () { + var stubAddBidResponse = sinon.stub(bidmanager, 'addBidResponse'); + + var response = null; // this is bogus: we expect an object + + adapter().callBids(params); + + var adUnits = []; + var unit = {}; + unit.bids = [params]; + unit.code = '/20164912/header-bid-tag'; + unit.sizes = [[300, 250], [728, 90]]; + adUnits.push(unit); + + if (typeof ($$PREBID_GLOBAL$$._bidsRequested) === 'undefined') { + $$PREBID_GLOBAL$$._bidsRequested = [params]; + } else { + $$PREBID_GLOBAL$$._bidsRequested.push(params); + } + $$PREBID_GLOBAL$$.adUnits = adUnits; + + $$PREBID_GLOBAL$$.handlePiximediaCallback(response); + + sinon.assert.notCalled(stubAddBidResponse); + + stubAddBidResponse.restore(); + }); + }); +}); diff --git a/test/spec/modules/prebidServerBidAdapter_spec.js b/test/spec/modules/prebidServerBidAdapter_spec.js new file mode 100644 index 00000000000..391d787772e --- /dev/null +++ b/test/spec/modules/prebidServerBidAdapter_spec.js @@ -0,0 +1,366 @@ +import { expect } from 'chai'; +import Adapter from 'modules/prebidServerBidAdapter'; +import bidmanager from 'src/bidmanager'; +import CONSTANTS from 'src/constants.json'; +import * as utils from 'src/utils'; +import cookie from 'src/cookie'; + +let CONFIG = { + accountId: '1', + enabled: true, + bidders: ['appnexus'], + timeout: 1000, + endpoint: CONSTANTS.S2S.DEFAULT_ENDPOINT +}; + +const REQUEST = { + 'account_id': '1', + 'tid': '437fbbf5-33f5-487a-8e16-a7112903cfe5', + 'max_bids': 1, + 'timeout_millis': 1000, + 'url': '', + 'prebid_version': '0.21.0-pre', + 'ad_units': [ + { + 'code': 'div-gpt-ad-1460505748561-0', + 'sizes': [ + { + 'w': 300, + 'h': 250 + }, + { + 'w': 300, + 'h': 600 + } + ], + 'transactionId': '4ef956ad-fd83-406d-bd35-e4bb786ab86c', + 'bids': [ + { + 'bid_id': '123', + 'bidder': 'appnexus', + 'params': { + 'placementId': '10433394', + 'member': 123 + } + } + ] + } + ] +}; + +const RESPONSE = { + 'tid': '437fbbf5-33f5-487a-8e16-a7112903cfe5', + 'status': 'OK', + 'bidder_status': [ + { + 'bidder': 'appnexus', + 'response_time_ms': 52, + 'num_bids': 1 + } + ], + 'bids': [ + { + 'bid_id': '123', + 'code': 'div-gpt-ad-1460505748561-0', + 'creative_id': '29681110', + 'bidder': 'appnexus', + 'price': 0.5, + 'adm': '', + 'width': 300, + 'height': 250, + 'deal_id': 'test-dealid' + } + ] +}; + +const RESPONSE_NO_BID_NO_UNIT = { + 'tid': '437fbbf5-33f5-487a-8e16-a7112903cfe5', + 'status': 'OK', + 'bidder_status': [{ + 'bidder': 'appnexus', + 'response_time_ms': 132, + 'no_bid': true + }] +}; + +const RESPONSE_NO_BID_UNIT_SET = { + 'tid': '437fbbf5-33f5-487a-8e16-a7112903cfe5', + 'status': 'OK', + 'bidder_status': [{ + 'bidder': 'appnexus', + 'ad_unit': 'div-gpt-ad-1460505748561-0', + 'response_time_ms': 91, + 'no_bid': true + }] +}; + +const RESPONSE_NO_COOKIE = { + 'tid': 'd6eca075-4a59-4346-bdb3-86531830ef2c', + 'status': 'OK', + 'bidder_status': [{ + 'bidder': 'pubmatic', + 'no_cookie': true, + 'usersync': { + 'url': '//ads.pubmatic.com/AdServer/js/user_sync.html?predirect=http://localhost:8000/setuid?bidder=pubmatic&uid=', + 'type': 'iframe' + } + }] +}; + +const RESPONSE_NO_PBS_COOKIE = { + 'tid': '882fe33e-2981-4257-bd44-bd3b03945f48', + 'status': 'no_cookie', + 'bidder_status': [{ + 'bidder': 'rubicon', + 'no_cookie': true, + 'usersync': { + 'url': 'https://pixel.rubiconproject.com/exchange/sync.php?p=prebid', + 'type': 'redirect' + } + }, { + 'bidder': 'pubmatic', + 'no_cookie': true, + 'usersync': { + 'url': '//ads.pubmatic.com/AdServer/js/user_sync.html?predirect=https%3A%2F%2Fprebid.adnxs.com%2Fpbs%2Fv1%2Fsetuid%3Fbidder%3Dpubmatic%26uid%3D', + 'type': 'iframe' + } + }, { + 'bidder': 'appnexus', + 'response_time_ms': 162, + 'num_bids': 1, + 'debug': [{ + 'request_uri': 'http://ib.adnxs.com/openrtb2', + 'request_body': '{"id":"882fe33e-2981-4257-bd44-bd3b03945f48","imp":[{"id":"/19968336/header-bid-tag-0","banner":{"w":300,"h":250,"format":[{"w":300,"h":250}]},"secure":1,"ext":{"appnexus":{"placement_id":5914989}}}],"site":{"domain":"nytimes.com","page":"http://www.nytimes.com"},"device":{"ua":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36","ip":"75.97.0.47"},"user":{"id":"3519479852893340159","buyeruid":"3519479852893340159"},"at":1,"tmax":1000,"source":{"fd":1,"tid":"882fe33e-2981-4257-bd44-bd3b03945f48"}}', + 'response_body': '{"id":"882fe33e-2981-4257-bd44-bd3b03945f48"}', + 'status_code': 200 + }] + }], + 'bids': [{ + 'bid_id': '123', + 'code': 'div-gpt-ad-1460505748561-0', + 'creative_id': '70928274', + 'bidder': 'appnexus', + 'price': 0.07425, + 'adm': '', + 'width': 300, + 'height': 250, + 'response_time_ms': 162 + }] +}; + +describe('S2S Adapter', () => { + let adapter; + + beforeEach(() => adapter = Adapter.createNew()); + + describe('request function', () => { + let xhr; + let requests; + + beforeEach(() => { + xhr = sinon.useFakeXMLHttpRequest(); + requests = []; + xhr.onCreate = request => requests.push(request); + }); + + afterEach(() => xhr.restore()); + + it('exists and is a function', () => { + expect(adapter.callBids).to.exist.and.to.be.a('function'); + }); + + it('exists converts types', () => { + adapter.setConfig(CONFIG); + adapter.callBids(REQUEST); + const requestBid = JSON.parse(requests[0].requestBody); + expect(requestBid.ad_units[0].bids[0].params.placementId).to.exist.and.to.be.a('number'); + expect(requestBid.ad_units[0].bids[0].params.member).to.exist.and.to.be.a('string'); + }); + }); + + describe('response handler', () => { + let server; + + beforeEach(() => { + server = sinon.fakeServer.create(); + sinon.stub(cookie, 'queueSync'); + sinon.stub(cookie, 'cookieSet'); + sinon.stub(bidmanager, 'addBidResponse'); + sinon.stub(utils, 'getBidderRequestAllAdUnits').returns({ + bids: [{ + bidId: '123', + placementCode: 'div-gpt-ad-1460505748561-0' + }] + }); + sinon.stub(utils, 'getBidRequest').returns({ + bidId: '123' + }); + }); + + afterEach(() => { + server.restore(); + bidmanager.addBidResponse.restore(); + utils.getBidderRequestAllAdUnits.restore(); + utils.getBidRequest.restore(); + cookie.queueSync.restore(); + cookie.cookieSet.restore(); + }); + + // TODO: test dependent on pbjs_api_spec. Needs to be isolated + it('registers bids', () => { + server.respondWith(JSON.stringify(RESPONSE)); + + adapter.setConfig(CONFIG); + adapter.callBids(REQUEST); + server.respond(); + sinon.assert.calledOnce(bidmanager.addBidResponse); + + const response = bidmanager.addBidResponse.firstCall.args[1]; + expect(response).to.have.property('statusMessage', 'Bid available'); + expect(response).to.have.property('cpm', 0.5); + expect(response).to.have.property('adId', '123'); + }); + + it('registers no-bid response when ad unit not set', () => { + server.respondWith(JSON.stringify(RESPONSE_NO_BID_NO_UNIT)); + + adapter.setConfig(CONFIG); + adapter.callBids(REQUEST); + server.respond(); + sinon.assert.calledOnce(bidmanager.addBidResponse); + + const ad_unit_code = bidmanager.addBidResponse.firstCall.args[0]; + expect(ad_unit_code).to.equal('div-gpt-ad-1460505748561-0'); + + const response = bidmanager.addBidResponse.firstCall.args[1]; + expect(response).to.have.property('statusMessage', 'Bid returned empty or error response'); + + const bid_request_passed = bidmanager.addBidResponse.firstCall.args[1]; + expect(bid_request_passed).to.have.property('adId', '123'); + }); + + it('registers no-bid response when server requests cookie sync', () => { + server.respondWith(JSON.stringify(RESPONSE_NO_COOKIE)); + + adapter.setConfig(CONFIG); + adapter.callBids(REQUEST); + server.respond(); + sinon.assert.calledOnce(bidmanager.addBidResponse); + + const ad_unit_code = bidmanager.addBidResponse.firstCall.args[0]; + expect(ad_unit_code).to.equal('div-gpt-ad-1460505748561-0'); + + const response = bidmanager.addBidResponse.firstCall.args[1]; + expect(response).to.have.property('statusMessage', 'Bid returned empty or error response'); + + const bid_request_passed = bidmanager.addBidResponse.firstCall.args[1]; + expect(bid_request_passed).to.have.property('adId', '123'); + }); + + it('registers no-bid response when ad unit is set', () => { + server.respondWith(JSON.stringify(RESPONSE_NO_BID_UNIT_SET)); + + adapter.setConfig(CONFIG); + adapter.callBids(REQUEST); + server.respond(); + sinon.assert.calledOnce(bidmanager.addBidResponse); + + const ad_unit_code = bidmanager.addBidResponse.firstCall.args[0]; + expect(ad_unit_code).to.equal('div-gpt-ad-1460505748561-0'); + + const response = bidmanager.addBidResponse.firstCall.args[1]; + expect(response).to.have.property('statusMessage', 'Bid returned empty or error response'); + }); + + it('registers no-bid response when there are less bids than requests', () => { + utils.getBidderRequestAllAdUnits.restore(); + sinon.stub(utils, 'getBidderRequestAllAdUnits').returns({ + bids: [{ + bidId: '123', + placementCode: 'div-gpt-ad-1460505748561-0' + }, { + bidId: '101111', + placementCode: 'div-gpt-ad-1460505748561-1' + }] + }); + + server.respondWith(JSON.stringify(RESPONSE)); + + adapter.setConfig(CONFIG); + adapter.callBids(REQUEST); + server.respond(); + + sinon.assert.calledTwice(bidmanager.addBidResponse); + + expect(bidmanager.addBidResponse.firstCall.args[0]).to.equal('div-gpt-ad-1460505748561-0'); + expect(bidmanager.addBidResponse.secondCall.args[0]).to.equal('div-gpt-ad-1460505748561-1'); + + expect(bidmanager.addBidResponse.firstCall.args[1]).to.have.property('adId', '123'); + expect(bidmanager.addBidResponse.secondCall.args[1]).to.have.property('adId', '101111'); + + expect(bidmanager.addBidResponse.firstCall.args[1]) + .to.have.property('statusMessage', 'Bid available'); + expect(bidmanager.addBidResponse.secondCall.args[1]) + .to.have.property('statusMessage', 'Bid returned empty or error response'); + }); + + it('should have dealId in bidObject', () => { + server.respondWith(JSON.stringify(RESPONSE)); + + adapter.setConfig(CONFIG); + adapter.callBids(REQUEST); + server.respond(); + const response = bidmanager.addBidResponse.firstCall.args[1]; + expect(response).to.have.property('dealId', 'test-dealid'); + }); + + it('registers bid responses when server requests cookie sync', () => { + server.respondWith(JSON.stringify(RESPONSE_NO_PBS_COOKIE)); + + adapter.setConfig(CONFIG); + adapter.callBids(REQUEST); + server.respond(); + sinon.assert.calledOnce(bidmanager.addBidResponse); + + const ad_unit_code = bidmanager.addBidResponse.firstCall.args[0]; + expect(ad_unit_code).to.equal('div-gpt-ad-1460505748561-0'); + + const response = bidmanager.addBidResponse.firstCall.args[1]; + expect(response).to.have.property('statusMessage', 'Bid available'); + expect(response).to.have.property('source', 's2s'); + + const bid_request_passed = bidmanager.addBidResponse.firstCall.args[1]; + expect(bid_request_passed).to.have.property('adId', '123'); + }); + + it('queue cookie sync when no_cookie response', () => { + server.respondWith(JSON.stringify(RESPONSE_NO_PBS_COOKIE)); + + adapter.setConfig(CONFIG); + adapter.callBids(REQUEST); + server.respond(); + sinon.assert.calledTwice(cookie.queueSync); + }); + + it('does not call cookieSet cookie sync when no_cookie response && not opted in', () => { + server.respondWith(JSON.stringify(RESPONSE_NO_PBS_COOKIE)); + + adapter.setConfig(CONFIG); + adapter.callBids(REQUEST); + server.respond(); + sinon.assert.notCalled(cookie.cookieSet); + }); + + it('calls cookieSet cookie sync when no_cookie response && opted in', () => { + server.respondWith(JSON.stringify(RESPONSE_NO_PBS_COOKIE)); + let config = Object.assign({ + cookieSet: true + }, CONFIG); + + adapter.setConfig(config); + adapter.callBids(REQUEST); + server.respond(); + sinon.assert.calledOnce(cookie.cookieSet); + }); + }); +}); diff --git a/test/spec/modules/pubgearsBidAdapter_spec.js b/test/spec/modules/pubgearsBidAdapter_spec.js new file mode 100644 index 00000000000..81f890e0dfd --- /dev/null +++ b/test/spec/modules/pubgearsBidAdapter_spec.js @@ -0,0 +1,287 @@ +import { expect } from 'chai'; +import Adapter from 'modules/pubgearsBidAdapter' +import bidmanager from 'src/bidmanager' + +describe('PubGearsAdapter', () => { + var adapter, mockScript, + params = { + bids: [] + } + + beforeEach(() => { + adapter = new Adapter() + mockScript = document.createElement('script') + sinon.spy(mockScript, 'setAttribute') + }) + + describe('request function', () => { + beforeEach(() => { + sinon.spy(document, 'createElement') + }) + + afterEach(() => { + document.createElement.restore && document.createElement.restore() + var s = document.getElementById('pg-header-tag') + if (s) { s.parentNode.removeChild(s) } + }) + + it('has `#callBids()` method', () => { + expect(adapter.callBids).to.exist.and.to.be.a('function') + }) + + it('requires bids to make script', () => { + adapter.callBids({bids: []}) + expect(document.createElement.notCalled).to.be.ok + }) + + it('creates script when passed bids', () => { + adapter.callBids({ + bidderCode: 'pubgears', + bids: [ + { + bidder: 'pubgears', + sizes: [ [300, 250] ], + adUnitCode: 'foo123/header-bid-tag', + params: { + publisherName: 'integration', + pubZone: 'testpub.com/combined' + } + } + ] + }) + + sinon.assert.calledWith(document.createElement, 'script') + }) + + it('should assign attributes to script', () => { + adapter.callBids({ + bidderCode: 'pubgears', + bids: [ + { + bidder: 'pubgears', + sizes: [ [300, 250] ], + adUnitCode: 'foo123/header-bid-tag', + params: { + publisherName: 'integration', + pubZone: 'testpub.com/combined' + } + }, + { + bidder: 'pubgears', + sizes: [ [160, 600] ], + adUnitCode: 'foo123/header-bid-tag', + params: { + publisherName: 'integration', + pubZone: 'testpub.com/combined' + } + } + ] + }) + var script = document.createElement.returnValues[0] + var slots = script.getAttribute('data-bsm-slot-list') + expect(slots).to.equal('testpub.com/combined@300x250 testpub.com/combined@160x600') + expect(script.getAttribute('data-bsm-flag')).to.equal('true') + expect(script.getAttribute('data-bsm-pub')).to.equal('integration') + expect(script.getAttribute('src')).to.equal('//c.pubgears.com/tags/h') + expect(script.id).to.equal('pg-header-tag') + }) + + it('should reuse existing script when called twice', () => { + var params = { + bidderCode: 'pubgears', + bids: [ + { + bidder: 'pubgears', + sizes: [ [300, 250] ], + adUnitCode: 'foo123/header-bid-tag', + params: { + publisherName: 'integration', + pubZone: 'testpub.com/combined' + } + }, + { + bidder: 'pubgears', + sizes: [ [160, 600] ], + adUnitCode: 'foo123/header-bid-tag', + params: { + publisherName: 'integration', + pubZone: 'testpub.com/combined' + } + } + ] + } + adapter.callBids(params) + expect(document.createElement.calledOnce).to.be.true + adapter.callBids(params) + expect(document.createElement.calledOnce).to.be.true + }) + + it('should register event listeners', () => { + var script = document.createElement('script') + script.id = 'pg-header-tag' + var spy = sinon.spy(script, 'addEventListener') + document.body.appendChild(script) + var params = { + bidderCode: 'pubgears', + bids: [ + { + bidder: 'pubgears', + sizes: [ [300, 250] ], + adUnitCode: 'foo123/header-bid-tag', + params: { + publisherName: 'integration', + pubZone: 'testpub.com/combined' + } + }, + { + bidder: 'pubgears', + sizes: [ [160, 600] ], + adUnitCode: 'foo123/header-bid-tag', + params: { + publisherName: 'integration', + pubZone: 'testpub.com/combined' + } + } + ] + } + adapter.callBids(params) + + expect(spy.calledWith('onBidResponse')).to.be.ok + expect(spy.calledWith('onResourceComplete')).to.be.ok + }) + }) + + describe('bids received', () => { + beforeEach(() => { + sinon.spy(bidmanager, 'addBidResponse') + }) + + afterEach(() => { + bidmanager.addBidResponse.restore() + }) + + it('should call bidManager.addBidResponse() when bid received', () => { + var options = { + bubbles: false, + cancelable: false, + detail: { + gross_price: 1000, + resource: { + position: 'atf', + pub_zone: 'testpub.com/combined', + size: '300x250' + } + } + } + + adapter.callBids({ + bidderCode: 'pubgears', + bids: [ + { + bidder: 'pubgears', + sizes: [ [300, 250] ], + adUnitCode: 'foo123/header-bid-tag', + params: { + publisherName: 'integration', + pubZone: 'testpub.com/combined' + } + }, + { + bidder: 'pubgears', + sizes: [ [160, 600] ], + adUnitCode: 'foo123/header-bid-tag', + params: { + publisherName: 'integration', + pubZone: 'testpub.com/combined' + } + } + ] + + }) + var script = document.getElementById('pg-header-tag') + var event = new CustomEvent('onBidResponse', options) + script.dispatchEvent(event) + + expect(bidmanager.addBidResponse.calledOnce).to.be.ok + }) + + it('should send correct bid response object when receiving onBidResponse event', () => { + expect(bidmanager.addBidResponse.calledOnce).to.not.be.ok + var bid = { + bidder: 'pubgears', + sizes: [ [300, 250] ], + adUnitCode: 'foo123/header-bid-tag', + params: { + publisherName: 'integration', + pubZone: 'testpub.com/combined' + } + } + + adapter.callBids({ + bidderCode: 'pubgears', + bids: [ bid ] + }) + + var options = { + bubbles: false, + cancelable: false, + detail: { + gross_price: 1000, + resource: { + position: 'atf', + pub_zone: 'testpub.com/combined', + size: '300x250' + } + } + } + var script = document.getElementById('pg-header-tag') + var event = new CustomEvent('onBidResponse', options) + script.dispatchEvent(event) + + var args = bidmanager.addBidResponse.getCall(1).args + expect(args).to.have.length(2) + var bidResponse = args[1] + expect(bidResponse.ad).to.contain(bid.params.pubZone) + }) + + it('should send $0 bid as no-bid response', () => { + var bid = { + bidder: 'pubgears', + sizes: [ [300, 250] ], + adUnitCode: 'foo123/header-bid-tag', + params: { + publisherName: 'integration', + pubZone: 'testpub.com/combined' + } + } + + adapter.callBids({ + bidderCode: 'pubgears', + bids: [ bid ] + }) + + var options = { + bubbles: false, + cancelable: false, + detail: { + gross_price: 0, + resource: { + position: 'atf', + pub_zone: 'testpub.com/combined', + size: '300x250' + } + } + } + var script = document.getElementById('pg-header-tag') + var event = new CustomEvent('onBidResponse', options) + + bidmanager.addBidResponse.reset() + script.dispatchEvent(event) + + var args = bidmanager.addBidResponse.getCall(1).args + var bidResponse = args[1] + expect(bidResponse).to.be.a('object') + expect(bidResponse.getStatusCode()).to.equal(2) + }) + }) +}) diff --git a/test/spec/modules/pubwiseAnalyticsAdapter_spec.js b/test/spec/modules/pubwiseAnalyticsAdapter_spec.js new file mode 100644 index 00000000000..4c3919172d8 --- /dev/null +++ b/test/spec/modules/pubwiseAnalyticsAdapter_spec.js @@ -0,0 +1,35 @@ +import pubwiseAnalytics from 'modules/pubwiseAnalyticsAdapter'; +let events = require('src/events'); +let adaptermanager = require('src/adaptermanager'); +let constants = require('src/constants.json'); + +describe('PubWise Prebid Analytics', function () { + describe('enableAnalytics', function () { + it('should catch all events', function () { + sinon.spy(pubwiseAnalytics, 'track'); + + adaptermanager.registerAnalyticsAdapter({ + code: 'pubwiseanalytics', + adapter: pubwiseAnalytics + }); + + adaptermanager.enableAnalytics({ + provider: 'pubwiseanalytics', + options: { + site: ['test-test-test-test'] + } + }); + + events.emit(constants.EVENTS.AUCTION_INIT, {}); + events.emit(constants.EVENTS.BID_REQUESTED, {}); + events.emit(constants.EVENTS.BID_RESPONSE, {}); + events.emit(constants.EVENTS.BID_WON, {}); + + events.emit(constants.EVENTS.AUCTION_END, {}); + events.emit(constants.EVENTS.BID_TIMEOUT, {}); + + /* testing for 6 calls, including the 2 we're not currently tracking */ + sinon.assert.callCount(pubwiseAnalytics.track, 6); + }); + }); +}); diff --git a/test/spec/adapters/pulsepoint_spec.js b/test/spec/modules/pulsepointBidAdapter_spec.js similarity index 86% rename from test/spec/adapters/pulsepoint_spec.js rename to test/spec/modules/pulsepointBidAdapter_spec.js index b3c24d38890..07639310c36 100644 --- a/test/spec/adapters/pulsepoint_spec.js +++ b/test/spec/modules/pulsepointBidAdapter_spec.js @@ -1,10 +1,9 @@ import {expect} from 'chai'; -import PulsePointAdapter from '../../../src/adapters/pulsepoint'; +import PulsePointAdapter from '../../../modules/pulsepointBidAdapter'; import bidManager from '../../../src/bidmanager'; import adLoader from '../../../src/adloader'; -describe("PulsePoint Adapter Tests", () => { - +describe('PulsePoint Adapter Tests', () => { let pulsepointAdapter = new PulsePointAdapter(); let slotConfigs; let requests = []; @@ -17,7 +16,7 @@ describe("PulsePoint Adapter Tests", () => { BID: 0 } }; - /* Ad object*/ + /* Ad object */ window.pp.Ad = function(config) { this.display = function() { requests.push(config); @@ -38,24 +37,24 @@ describe("PulsePoint Adapter Tests", () => { slotConfigs = { bids: [ { - placementCode: "/DfpAccount1/slot1", - bidder: "pulsepoint", + placementCode: '/DfpAccount1/slot1', + bidder: 'pulsepoint', bidId: 'bid12345', params: { - cp: "p10000", - ct: "t10000", - cf: "300x250", - param1: "value1", + cp: 'p10000', + ct: 't10000', + cf: '300x250', + param1: 'value1', param2: 2 } - },{ - placementCode: "/DfpAccount2/slot2", - bidder: "pulsepoint", + }, { + placementCode: '/DfpAccount2/slot2', + bidder: 'pulsepoint', bidId: 'bid23456', params: { - cp: "p20000", - ct: "t20000", - cf: "728x90" + cp: 'p20000', + ct: 't20000', + cf: '728x90' } } ] @@ -72,7 +71,7 @@ describe("PulsePoint Adapter Tests", () => { it('Verify requests sent to PulsePoint library', () => { pulsepointAdapter.callBids(slotConfigs); expect(requests).to.have.length(2); - //slot 1 + // slot 1 expect(requests[0].cp).to.equal('p10000'); expect(requests[0].ct).to.equal('t10000'); expect(requests[0].cf).to.equal('300x250'); @@ -138,7 +137,7 @@ describe("PulsePoint Adapter Tests", () => { let bidCall = bidManager.addBidResponse.firstCall; expect(callback).to.be.a('function'); expect(bidCall).to.be.a('null'); - //the library load should initialize pulsepoint lib + // the library load should initialize pulsepoint lib initPulsepointLib(); callback(); expect(requests.length).to.equal(2); @@ -148,18 +147,17 @@ describe("PulsePoint Adapter Tests", () => { expect(bidCall.args[1]).to.be.a('object'); }); - //related to issue https://github.com/prebid/Prebid.js/issues/866 + // related to issue https://github.com/prebid/Prebid.js/issues/866 it('Verify Passbacks when window.pp is not available', () => { window.pp = function() {}; pulsepointAdapter.callBids(slotConfigs); let placement = bidManager.addBidResponse.firstCall.args[0]; let bid = bidManager.addBidResponse.firstCall.args[1]; - //verify that we passed back without exceptions, should window.pp be already taken. + // verify that we passed back without exceptions, should window.pp be already taken. expect(placement).to.equal('/DfpAccount1/slot1'); expect(bid.bidderCode).to.equal('pulsepoint'); expect(bid).to.not.have.property('ad'); expect(bid).to.not.have.property('cpm'); expect(bid.adId).to.equal('bid12345'); }); - }); diff --git a/test/spec/modules/pulsepointLiteBidAdapter_spec.js b/test/spec/modules/pulsepointLiteBidAdapter_spec.js new file mode 100644 index 00000000000..2a8b09245a2 --- /dev/null +++ b/test/spec/modules/pulsepointLiteBidAdapter_spec.js @@ -0,0 +1,234 @@ +import {expect} from 'chai'; +import PulsePointAdapter from 'modules/pulsepointLiteBidAdapter'; +import bidManager from 'src/bidmanager'; +import {getTopWindowLocation} from 'src/utils'; +import * as ajax from 'src/ajax'; + +describe('PulsePoint Lite Adapter Tests', () => { + let pulsepointAdapter = new PulsePointAdapter(); + let slotConfigs; + let nativeSlotConfig; + let ajaxStub; + + beforeEach(() => { + sinon.stub(bidManager, 'addBidResponse'); + ajaxStub = sinon.stub(ajax, 'ajax'); + + slotConfigs = { + bidderCode: 'pulseLite', + bids: [ + { + placementCode: '/DfpAccount1/slot1', + bidId: 'bid12345', + params: { + cp: 'p10000', + ct: 't10000', + cf: '300x250' + } + }, { + placementCode: '/DfpAccount2/slot2', + bidId: 'bid23456', + params: { + cp: 'p10000', + ct: 't20000', + cf: '728x90' + } + } + ] + }; + nativeSlotConfig = { + bidderCode: 'pulseLite', + bids: [ + { + placementCode: '/DfpAccount1/slot3', + bidId: 'bid12345', + nativeParams: { + title: { required: true, len: 200 }, + image: { wmin: 100 }, + sponsoredBy: { } + }, + params: { + cp: 'p10000', + ct: 't10000' + } + } + ] + }; + }); + + afterEach(() => { + bidManager.addBidResponse.restore(); + ajaxStub.restore(); + }); + + it('Verify requests sent to PulsePoint', () => { + pulsepointAdapter.callBids(slotConfigs); + expect(ajaxStub.callCount).to.equal(1); + expect(ajaxStub.firstCall.args[0]).to.equal('http://bid.contextweb.com/header/ortb'); + const ortbRequest = JSON.parse(ajaxStub.firstCall.args[2]); + // site object + expect(ortbRequest.site).to.not.equal(null); + expect(ortbRequest.site.publisher).to.not.equal(null); + expect(ortbRequest.site.publisher.id).to.equal('p10000'); + expect(ortbRequest.site.ref).to.equal(window.top.document.referrer); + expect(ortbRequest.site.page).to.equal(getTopWindowLocation().href); + expect(ortbRequest.imp).to.have.lengthOf(2); + // device object + expect(ortbRequest.device).to.not.equal(null); + expect(ortbRequest.device.ua).to.equal(navigator.userAgent); + // slot 1 + expect(ortbRequest.imp[0].tagid).to.equal('t10000'); + expect(ortbRequest.imp[0].banner).to.not.equal(null); + expect(ortbRequest.imp[0].banner.w).to.equal(300); + expect(ortbRequest.imp[0].banner.h).to.equal(250); + // slot 2 + expect(ortbRequest.imp[1].tagid).to.equal('t20000'); + expect(ortbRequest.imp[1].banner).to.not.equal(null); + expect(ortbRequest.imp[1].banner.w).to.equal(728); + expect(ortbRequest.imp[1].banner.h).to.equal(90); + }); + + it('Verify bid', () => { + pulsepointAdapter.callBids(slotConfigs); + // trigger a mock ajax callback with bid. + const ortbRequest = JSON.parse(ajaxStub.firstCall.args[2]); + ajaxStub.firstCall.args[1](JSON.stringify({ + seatbid: [{ + bid: [{ + impid: ortbRequest.imp[0].id, + price: 1.25, + adm: 'This is an Ad' + }] + }] + })); + expect(bidManager.addBidResponse.callCount).to.equal(2); + // verify first bid + let placement = bidManager.addBidResponse.firstCall.args[0]; + let bid = bidManager.addBidResponse.firstCall.args[1]; + expect(placement).to.equal('/DfpAccount1/slot1'); + expect(bid.bidderCode).to.equal('pulseLite'); + expect(bid.cpm).to.equal(1.25); + expect(bid.ad).to.equal('This is an Ad'); + expect(bid.width).to.equal(300); + expect(bid.height).to.equal(250); + expect(bid.adId).to.equal('bid12345'); + // verify passback on 2nd impression. + placement = bidManager.addBidResponse.secondCall.args[0]; + bid = bidManager.addBidResponse.secondCall.args[1]; + expect(placement).to.equal('/DfpAccount2/slot2'); + expect(bid.adId).to.equal('bid23456'); + expect(bid.bidderCode).to.equal('pulseLite'); + expect(bid.cpm).to.be.undefined; + }); + + it('Verify full passback', () => { + pulsepointAdapter.callBids(slotConfigs); + // trigger a mock ajax callback with no bid. + ajaxStub.firstCall.args[1](null); + let placement = bidManager.addBidResponse.firstCall.args[0]; + let bid = bidManager.addBidResponse.firstCall.args[1]; + expect(placement).to.equal('/DfpAccount1/slot1'); + expect(bid.bidderCode).to.equal('pulseLite'); + expect(bid).to.not.have.property('ad'); + expect(bid).to.not.have.property('cpm'); + expect(bid.adId).to.equal('bid12345'); + }); + + it('Verify passback when ajax call fails', () => { + ajaxStub.throws(); + pulsepointAdapter.callBids(slotConfigs); + let placement = bidManager.addBidResponse.firstCall.args[0]; + let bid = bidManager.addBidResponse.firstCall.args[1]; + expect(placement).to.equal('/DfpAccount1/slot1'); + expect(bid.bidderCode).to.equal('pulseLite'); + expect(bid).to.not.have.property('ad'); + expect(bid).to.not.have.property('cpm'); + expect(bid.adId).to.equal('bid12345'); + }); + + it('Verify Native request', () => { + pulsepointAdapter.callBids(nativeSlotConfig); + expect(ajaxStub.callCount).to.equal(1); + expect(ajaxStub.firstCall.args[0]).to.equal('http://bid.contextweb.com/header/ortb'); + const ortbRequest = JSON.parse(ajaxStub.firstCall.args[2]); + // native impression + expect(ortbRequest.imp[0].tagid).to.equal('t10000'); + expect(ortbRequest.imp[0].banner).to.equal(null); + expect(ortbRequest.imp[0].native).to.not.equal(null); + expect(ortbRequest.imp[0].native.ver).to.equal('1.1'); + expect(ortbRequest.imp[0].native.request).to.not.equal(null); + // native request assets + const nativeRequest = JSON.parse(ortbRequest.imp[0].native.request); + expect(nativeRequest).to.not.equal(null); + expect(nativeRequest.assets).to.have.lengthOf(3); + // title asset + expect(nativeRequest.assets[0].id).to.equal(1); + expect(nativeRequest.assets[0].required).to.equal(1); + expect(nativeRequest.assets[0].title).to.not.equal(null); + expect(nativeRequest.assets[0].title.len).to.equal(200); + // data asset + expect(nativeRequest.assets[1].id).to.equal(2); + expect(nativeRequest.assets[1].required).to.equal(0); + expect(nativeRequest.assets[1].title).to.be.undefined; + expect(nativeRequest.assets[1].data).to.not.equal(null); + expect(nativeRequest.assets[1].data.type).to.equal(1); + expect(nativeRequest.assets[1].data.len).to.equal(50); + // image asset + expect(nativeRequest.assets[2].id).to.equal(3); + expect(nativeRequest.assets[2].required).to.equal(0); + expect(nativeRequest.assets[2].title).to.be.undefined; + expect(nativeRequest.assets[2].img).to.not.equal(null); + expect(nativeRequest.assets[2].img.wmin).to.equal(100); + expect(nativeRequest.assets[2].img.hmin).to.equal(150); + expect(nativeRequest.assets[2].img.type).to.equal(3); + }); + + it('Verify Native response', () => { + pulsepointAdapter.callBids(nativeSlotConfig); + expect(ajaxStub.callCount).to.equal(1); + expect(ajaxStub.firstCall.args[0]).to.equal('http://bid.contextweb.com/header/ortb'); + const ortbRequest = JSON.parse(ajaxStub.firstCall.args[2]); + const nativeResponse = { + native: { + assets: [ + { title: { text: 'Ad Title'} }, + { data: { type: 1, value: 'Sponsored By: Brand' }}, + { img: { type: 3, url: 'http://images.cdn.brand.com/123' } } + ], + link: { url: 'http://brand.clickme.com/' }, + imptrackers: [ 'http://imp1.trackme.com/', 'http://imp1.contextweb.com/' ] + } + }; + ajaxStub.firstCall.args[1](JSON.stringify({ + seatbid: [{ + bid: [{ + impid: ortbRequest.imp[0].id, + price: 1.25, + adm: JSON.stringify(nativeResponse) + }] + }] + })); + // verify bid + let placement = bidManager.addBidResponse.firstCall.args[0]; + let bid = bidManager.addBidResponse.firstCall.args[1]; + expect(placement).to.equal('/DfpAccount1/slot3'); + expect(bid.bidderCode).to.equal('pulseLite'); + expect(bid.cpm).to.equal(1.25); + expect(bid.adId).to.equal('bid12345'); + expect(bid.ad).to.be.undefined; + expect(bid.mediaType).to.equal('native'); + expect(bid.native).to.not.equal(null); + expect(bid.native.title).to.equal('Ad Title'); + expect(bid.native.sponsoredBy).to.equal('Sponsored By: Brand'); + expect(bid.native.image).to.equal('http://images.cdn.brand.com/123'); + expect(bid.native.clickUrl).to.equal(encodeURIComponent('http://brand.clickme.com/')); + expect(bid.native.impressionTrackers).to.have.lengthOf(2); + expect(bid.native.impressionTrackers[0]).to.equal('http://imp1.trackme.com/'); + expect(bid.native.impressionTrackers[1]).to.equal('http://imp1.contextweb.com/'); + }); + + it('Verify createNew', function () { + const adapter = PulsePointAdapter.createNew(); + expect(adapter).to.have.property('callBids'); + }); +}); diff --git a/test/spec/adapters/quantcast_spec.js b/test/spec/modules/quantcastBidAdapter_spec.js similarity index 67% rename from test/spec/adapters/quantcast_spec.js rename to test/spec/modules/quantcastBidAdapter_spec.js index ceca035d671..0d139ac3ec2 100644 --- a/test/spec/adapters/quantcast_spec.js +++ b/test/spec/modules/quantcastBidAdapter_spec.js @@ -1,11 +1,10 @@ import {expect} from 'chai'; -import Adapter from '../../../src/adapters/quantcast'; +import Adapter from '../../../modules/quantcastBidAdapter'; import * as ajax from 'src/ajax'; import bidManager from '../../../src/bidmanager'; import adLoader from '../../../src/adloader'; describe('quantcast adapter', () => { - let bidsRequestedOriginal; let adapter; let sandbox; @@ -13,17 +12,17 @@ describe('quantcast adapter', () => { const bidderRequest = { bidderCode: 'quantcast', - requestId : "595ffa73-d78a-46c9-b18e-f99548a5be6b", - bidderRequestId:"1cc026909c24c8", + requestId: '595ffa73-d78a-46c9-b18e-f99548a5be6b', + bidderRequestId: '1cc026909c24c8', bids: [ { bidId: '2f7b179d443f14', bidder: 'quantcast', placementCode: 'div-gpt-ad-1438287399331-0', - sizes: [[300,250],[300,600]], + sizes: [[300, 250], [300, 600]], params: { publisherId: 'test-publisher', - battr : [1,2], + battr: [1, 2], } } ] @@ -47,17 +46,17 @@ describe('quantcast adapter', () => { describe('sizes', () => { let bidderRequest = { bidderCode: 'quantcast', - requestId : "595ffa73-d78a-46c9-b18e-f99548a5be6b", - bidderRequestId:"1cc026909c24c8", + requestId: '595ffa73-d78a-46c9-b18e-f99548a5be6b', + bidderRequestId: '1cc026909c24c8', bids: [ { bidId: '2f7b179d443f14', bidder: 'quantcast', placementCode: 'div-gpt-ad-1438287399331-0', - sizes: [[300,250],[300,600]], + sizes: [[300, 250], [300, 600]], params: { publisherId: 'test-publisher', - battr : [1,2], + battr: [1, 2], } } ] @@ -77,7 +76,7 @@ describe('quantcast adapter', () => { expect(ajaxStub.firstCall.args[2]).to.include('div-gpt-ad-1438287399331-0'); expect(ajaxStub.firstCall.args[2]).to.include('test-publisher'); expect(ajaxStub.firstCall.args[2]).to.include('2f7b179d443f14'); - expect(ajaxStub.firstCall.args[3]).to.eql({method : 'POST', withCredentials: true}); + expect(ajaxStub.firstCall.args[3]).to.eql({method: 'POST', withCredentials: true}); }); it('should call server once when one size is passed', () => { @@ -87,51 +86,48 @@ describe('quantcast adapter', () => { expect(ajaxStub.firstCall.args[0]).to.eql(adapter.QUANTCAST_CALLBACK_URL); expect(ajaxStub.firstCall.args[1]).to.exist.and.to.be.a('function'); - expect(ajaxStub.firstCall.args[3]).to.eql({method : 'POST', withCredentials: true}); + expect(ajaxStub.firstCall.args[3]).to.eql({method: 'POST', withCredentials: true}); }); it('should call server once when size is passed as string', () => { - bidderRequest.bids[0].sizes = "728x90"; + bidderRequest.bids[0].sizes = '728x90'; adapter.callBids(bidderRequest); sinon.assert.calledOnce(ajaxStub); expect(ajaxStub.firstCall.args[0]).to.eql(adapter.QUANTCAST_CALLBACK_URL); expect(ajaxStub.firstCall.args[1]).to.exist.and.to.be.a('function'); - expect(ajaxStub.firstCall.args[3]).to.eql({method : 'POST', withCredentials: true}); + expect(ajaxStub.firstCall.args[3]).to.eql({method: 'POST', withCredentials: true}); }); it('should call server once when sizes are passed as a comma-separated string', () => { - bidderRequest.bids[0].sizes = "728x90,360x240"; + bidderRequest.bids[0].sizes = '728x90,360x240'; adapter.callBids(bidderRequest); sinon.assert.calledOnce(ajaxStub); expect(ajaxStub.firstCall.args[0]).to.eql(adapter.QUANTCAST_CALLBACK_URL); expect(ajaxStub.firstCall.args[1]).to.exist.and.to.be.a('function'); - expect(ajaxStub.firstCall.args[3]).to.eql({method : 'POST', withCredentials: true}); + expect(ajaxStub.firstCall.args[3]).to.eql({method: 'POST', withCredentials: true}); }); - - }); describe('handleQuantcastCB add bids to the manager', () => { - let firstBid; let addBidReponseStub; let bidsRequestedOriginal; // respond let bidderReponse = { - "bidderCode": "quantcast", - "requestId" : bidderRequest.requestId, - "bids" : [ - { - "statusCode" : 1, - "placementCode" : bidderRequest.bids[0].bidId, - "cpm": 4.5, - "ad": "\n\n\n
\n
\n\n \n\n\"Quantcast\"/\n\n
\n
", - "width": 300, - "height": 250 - } - ] + 'bidderCode': 'quantcast', + 'requestId': bidderRequest.requestId, + 'bids': [ + { + 'statusCode': 1, + 'placementCode': bidderRequest.bids[0].bidId, + 'cpm': 4.5, + 'ad': '\n\n\n
\n
\n\n \n\nQuantcast\n\n
\n
', + 'width': 300, + 'height': 250 + } + ] }; beforeEach(() => { @@ -169,26 +165,25 @@ describe('quantcast adapter', () => { adapter.callBids(bidderRequest); $$PREBID_GLOBAL$$.handleQuantcastCB(JSON.stringify(bidderReponse)); sinon.assert.calledOnce(addBidReponseStub); - expect(addBidReponseStub.firstCall.args[0]).to.eql("div-gpt-ad-1438287399331-0"); + expect(addBidReponseStub.firstCall.args[0]).to.eql('div-gpt-ad-1438287399331-0'); }); - it('should return no bid even when requestId and sizes are missing', () =>{ + it('should return no bid even when requestId and sizes are missing', () => { let bidderReponse = { - "bidderCode": "quantcast", - "bids" : [ - { - "statusCode" : 0, - "placementCode" : bidderRequest.bids[0].bidId, - } - ] - }; + 'bidderCode': 'quantcast', + 'bids': [ + { + 'statusCode': 0, + 'placementCode': bidderRequest.bids[0].bidId, + } + ] + }; // You need the following call so that the in-memory storage of the bidRequest is carried out. Without this the callback won't work correctly. adapter.callBids(bidderRequest); $$PREBID_GLOBAL$$.handleQuantcastCB(JSON.stringify(bidderReponse)); - //sinon.assert.calledOnce(addBidReponseStub); - //expect(addBidReponseStub.firstCall.args[0]).to.eql("div-gpt-ad-1438287399331-0"); + // sinon.assert.calledOnce(addBidReponseStub); + // expect(addBidReponseStub.firstCall.args[0]).to.eql("div-gpt-ad-1438287399331-0"); }); }); - }); diff --git a/test/spec/modules/rhythmoneBidAdapter_spec.js b/test/spec/modules/rhythmoneBidAdapter_spec.js new file mode 100644 index 00000000000..002d021b574 --- /dev/null +++ b/test/spec/modules/rhythmoneBidAdapter_spec.js @@ -0,0 +1,90 @@ +var r1 = require('../../../modules/rhythmoneBidAdapter'); +var assert = require('assert'); + +describe('rhythmone adapter tests', function () { + describe('rhythmoneResponse', function () { + var fakeResponse = { + 'id': '1fe94c2e-4b31-4e09-b074-ba90fe7ce92d', + 'seatbid': [ + { + 'bid': [ + { + 'id': 'ff8b09b1-5264-52be-4b7b-0156526452bf', + 'impid': 'div-gpt-ad-1438287399331-0', + 'price': 1.0, + 'adid': '35858', + 'adm': "\"\"", + 'adomain': ['www.rhythmone.com'], + 'cid': '35857', + 'cat': [], + 'h': 250, + 'w': 300 + } + ], + 'seat': '14', + 'group': 0 + } + ], + 'bidid': 'ff8b09b1-5264-52be-4b7b-0156526452bf' + }; + + var endEvent = function() {}, + wonEvent = function() {}; ; + + var z = new r1( + { + addBidResponse: function(placementcode, adResponse) { + it('should echo placementcode div-gpt-ad-1438287399331-0', function() { + assert.equal(placementcode, 'div-gpt-ad-1438287399331-0'); + }); + it('should have the expected ad response', function() { + assert.equal((adResponse.ad === undefined || adResponse.ad.length > 0), true); + assert.equal(adResponse.width, 300); + assert.equal(adResponse.height, 250); + assert.equal(adResponse.cpm, 1); + assert.equal(adResponse.bidderCode, 'rhythmone'); + }); + } + }, + { + 'navigator': {}, + 'pbjs': { + 'onEvent': function(e, f) { + if (e.toLowerCase() === 'auctionend') endEvent = f; + if (e.toLowerCase() === 'bidwon') wonEvent = f; + }, + 'getBidResponses': function() { return {'div-gpt-ad-1438287399331-0': {'bids': [{cpm: 1, bidderCode: 'rhythmone'}, {cpm: 2, bidderCode: 'rhythmone'}]}}; }, + 'version': 'v0.20.0-pre' + } + }, + function(url, callback) { + callback(JSON.stringify(fakeResponse), {status: 200, responseText: JSON.stringify(fakeResponse)}); + }); + + z.callBids({ + 'bidderCode': 'rhythmone', + 'bids': [ + { + 'bidder': 'rhythmone', + 'params': { + 'placementId': 'xyz', + 'keywords': '', + 'categories': [], + 'trace': true, + 'method': 'get', + 'endpoint': 'http://fakedomain.com' + }, + 'mediaType': 'video', + 'placementCode': 'div-gpt-ad-1438287399331-0', + 'sizes': [[300, 250]] + } + ] + }); + + endEvent(); + wonEvent({ + bidderCode: 'rhythmone', + adUnitCode: 'div-gpt-ad-1438287399331-0' + }); + }); +}); diff --git a/test/spec/adapters/analytics/roxot_analytic_spec.js b/test/spec/modules/roxotAnalyticsAdapter_spec.js similarity index 77% rename from test/spec/adapters/analytics/roxot_analytic_spec.js rename to test/spec/modules/roxotAnalyticsAdapter_spec.js index fd19ca464a8..fbd298c7e3b 100644 --- a/test/spec/adapters/analytics/roxot_analytic_spec.js +++ b/test/spec/modules/roxotAnalyticsAdapter_spec.js @@ -1,13 +1,10 @@ -import roxotAnalytic from 'src/adapters/analytics/roxot'; -let events = require('../../../../src/events'); -let adaptermanager = require('../../../../src/adaptermanager'); -let constants = require('../../../../src/constants.json'); +import roxotAnalytic from 'modules/roxotAnalyticsAdapter'; +let events = require('src/events'); +let adaptermanager = require('src/adaptermanager'); +let constants = require('src/constants.json'); describe('Roxot Prebid Analytic', function () { - describe('enableAnalytics', function () { - - it('should catch all events', function () { sinon.spy(roxotAnalytic, 'track'); diff --git a/test/spec/adapters/roxot_spec.js b/test/spec/modules/roxotBidAdapter_spec.js similarity index 82% rename from test/spec/adapters/roxot_spec.js rename to test/spec/modules/roxotBidAdapter_spec.js index 468d3f22ce1..af7bef291e1 100644 --- a/test/spec/adapters/roxot_spec.js +++ b/test/spec/modules/roxotBidAdapter_spec.js @@ -1,12 +1,11 @@ -describe('Roxot adapter tests', function(){ +describe('Roxot adapter tests', function() { const expect = require('chai').expect; - const adapter = require('src/adapters/roxot'); + const adapter = require('modules/roxotBidAdapter'); const bidmanager = require('src/bidmanager'); describe('roxotResponseHandler', function () { - it('should exist and be a function', function () { - expect(pbjs.roxotResponseHandler).to.exist.and.to.be.a('function'); + expect($$PREBID_GLOBAL$$.roxotResponseHandler).to.exist.and.to.be.a('function'); }); it('should add empty bid responses if no bids returned', function () { @@ -30,19 +29,18 @@ describe('Roxot adapter tests', function(){ ] }; - // no bids returned in the response. var response = { - "id": "123", - "bids": [] + 'id': '123', + 'bids': [] }; - pbjs._bidsRequested.push(bidderRequest); + $$PREBID_GLOBAL$$._bidsRequested.push(bidderRequest); // adapter needs to be called, in order for the stub to register. adapter(); - pbjs.roxotResponseHandler(response); + $$PREBID_GLOBAL$$.roxotResponseHandler(response); var bidPlacementCode1 = stubAddBidResponse.getCall(0).args[0]; var bidObject1 = stubAddBidResponse.getCall(0).args[1]; @@ -61,7 +59,6 @@ describe('Roxot adapter tests', function(){ }); it('should add a bid response for bids returned and empty bid responses for the rest', () => { - var stubAddBidResponse = sinon.stub(bidmanager, 'addBidResponse'); var bidderRequest = { @@ -84,24 +81,24 @@ describe('Roxot adapter tests', function(){ // Returning a single bid in the response. var response = { - "id": "12345", - "bids": [ + 'id': '12345', + 'bids': [ { - "bidId" : "id1", - "cpm" : 0.09, - "nurl" : "http://roxot.example.com", - "adm" : "<>", - "h" : 320, - "w" : 50 + 'bidId': 'id1', + 'cpm': 0.09, + 'nurl': 'http://roxot.example.com', + 'adm': '<>', + 'h': 320, + 'w': 50 } ]}; - pbjs._bidsRequested.push(bidderRequest); + $$PREBID_GLOBAL$$._bidsRequested.push(bidderRequest); // adapter needs to be called, in order for the stub to register. adapter(); - pbjs.roxotResponseHandler(response); + $$PREBID_GLOBAL$$.roxotResponseHandler(response); var bidPlacementCode1 = stubAddBidResponse.getCall(0).args[0]; var bidObject1 = stubAddBidResponse.getCall(0).args[1]; @@ -123,4 +120,4 @@ describe('Roxot adapter tests', function(){ stubAddBidResponse.restore(); }); }); -}); \ No newline at end of file +}); diff --git a/test/spec/adapters/rubicon_spec.js b/test/spec/modules/rubiconBidAdapter_spec.js similarity index 82% rename from test/spec/adapters/rubicon_spec.js rename to test/spec/modules/rubiconBidAdapter_spec.js index d164f3da096..d2092d9a1eb 100644 --- a/test/spec/adapters/rubicon_spec.js +++ b/test/spec/modules/rubiconBidAdapter_spec.js @@ -1,8 +1,7 @@ import { expect } from 'chai'; -import adloader from 'src/adloader'; import adapterManager from 'src/adaptermanager'; import bidManager from 'src/bidmanager'; -import RubiconAdapter from 'src/adapters/rubicon'; +import RubiconAdapter from 'modules/rubiconBidAdapter'; import {parse as parseQuery} from 'querystring'; var CONSTANTS = require('src/constants.json'); @@ -10,10 +9,9 @@ var CONSTANTS = require('src/constants.json'); const INTEGRATION = `pbjs_lite_v$prebid.version$`; // $prebid.version$ will be substituted in by gulp in built prebid describe('the rubicon adapter', () => { - let sandbox, - adUnit, - bidderRequest; + adUnit, + bidderRequest; function createVideoBidderRequest() { let bid = bidderRequest.bids[0]; @@ -68,14 +66,14 @@ describe('the rubicon adapter', () => { siteId: '70608', zoneId: '335918', userId: '12346', - keywords: ['a','b','c'], + keywords: ['a', 'b', 'c'], inventory: { - rating:'5-star', - prodtype:'tech' + rating: '5-star', + prodtype: 'tech' }, visitor: { - ucat:'new', - lastsearch:'iphone' + ucat: 'new', + lastsearch: 'iphone' }, position: 'atf', referrer: 'localhost' @@ -96,14 +94,14 @@ describe('the rubicon adapter', () => { siteId: '70608', zoneId: '335918', userId: '12346', - keywords: ['a','b','c'], + keywords: ['a', 'b', 'c'], inventory: { - rating:'5-star', - prodtype:'tech' + rating: '5-star', + prodtype: 'tech' }, visitor: { - ucat:'new', - lastsearch:'iphone' + ucat: 'new', + lastsearch: 'iphone' }, position: 'atf', referrer: 'localhost' @@ -119,7 +117,6 @@ describe('the rubicon adapter', () => { auctionStart: 1472239426000, timeout: 5000 }; - }); afterEach(() => { @@ -127,11 +124,9 @@ describe('the rubicon adapter', () => { }); describe('callBids public interface', () => { - let rubiconAdapter = adapterManager.bidderRegistry['rubicon']; it('should receive a well-formed bidRequest from the adaptermanager', () => { - sandbox.stub(rubiconAdapter, 'callBids'); adapterManager.callBids({ @@ -161,14 +156,11 @@ describe('the rubicon adapter', () => { expect(bidderRequest).to.have.deep.property('bids[0]') .with.property('params') - .that.deep.equals(adUnit.bids[0].params) - + .that.deep.equals(adUnit.bids[0].params); }); - }); describe('MAS mapping / ordering', () => { - let masSizeOrdering = RubiconAdapter.masSizeOrdering; it('should not include values without a proper mapping', () => { @@ -185,26 +177,23 @@ describe('the rubicon adapter', () => { }); it('should sort MAS priority sizes in the proper order w/ rest ascending', () => { - let ordering = masSizeOrdering([[320, 50], [160,600], [640, 480], [300, 250],[336, 280], [200, 600]]); + let ordering = masSizeOrdering([[320, 50], [160, 600], [640, 480], [300, 250], [336, 280], [200, 600]]); expect(ordering).to.deep.equal([15, 9, 16, 43, 65, 126]); - ordering = masSizeOrdering([[320, 50], [300, 250], [160,600], [640, 480],[336, 280], [200, 600], [728, 90]]); + ordering = masSizeOrdering([[320, 50], [300, 250], [160, 600], [640, 480], [336, 280], [200, 600], [728, 90]]); expect(ordering).to.deep.equal([15, 2, 9, 16, 43, 65, 126]); - ordering = masSizeOrdering([[120, 600], [320, 50], [160,600], [640, 480],[336, 280], [200, 600], [728, 90]]); + ordering = masSizeOrdering([[120, 600], [320, 50], [160, 600], [640, 480], [336, 280], [200, 600], [728, 90]]); expect(ordering).to.deep.equal([2, 9, 8, 16, 43, 65, 126]); }); - }); describe('callBids implementation', () => { - let rubiconAdapter; describe('for requests', () => { - let xhr, - bids; + bids; beforeEach(() => { rubiconAdapter = new RubiconAdapter(); @@ -223,9 +212,7 @@ describe('the rubicon adapter', () => { }); describe('to fastlane', () => { - it('should make a well-formed request', () => { - rubiconAdapter.callBids(bidderRequest); let request = xhr.requests[0]; @@ -245,6 +232,7 @@ describe('the rubicon adapter', () => { 'alt_size_ids': '43', 'p_pos': 'atf', 'rp_floor': '0.01', + 'rp_secure': /[01]/, 'tk_flint': INTEGRATION, 'p_screen_res': /\d+x\d+/, 'tk_user_key': '12346', @@ -259,7 +247,7 @@ describe('the rubicon adapter', () => { // test that all values above are both present and correct Object.keys(expectedQuery).forEach(key => { let value = expectedQuery[key]; - if(value instanceof RegExp) { + if (value instanceof RegExp) { expect(query[key]).to.match(value); } else { expect(query[key]).to.equal(value); @@ -267,11 +255,9 @@ describe('the rubicon adapter', () => { }); expect(query).to.have.property('rand'); - }); it('should use rubicon sizes if present', () => { - var sizesBidderRequest = clone(bidderRequest); sizesBidderRequest.bids[0].params.sizes = [55, 57, 59]; @@ -281,13 +267,11 @@ describe('the rubicon adapter', () => { expect(query['size_id']).to.equal('55'); expect(query['alt_size_ids']).to.equal('57,59'); - }); - - it('should not send a request and register an error bid if no valid sizes', () => { + it('should not send a request and register an error bid if no valid sizes', () => { var sizesBidderRequest = clone(bidderRequest); - sizesBidderRequest.bids[0].sizes = [[620,250],[300,251]]; + sizesBidderRequest.bids[0].sizes = [[620, 250], [300, 251]]; rubiconAdapter.callBids(sizesBidderRequest); @@ -296,11 +280,9 @@ describe('the rubicon adapter', () => { expect(bidManager.addBidResponse.calledOnce).to.equal(true); expect(bids).to.be.lengthOf(1); expect(bids[0].getStatusCode()).to.equal(CONSTANTS.STATUS.NO_BID); - }); it('should not send a request and register an error if no account id is present', () => { - var noAccountBidderRequest = clone(bidderRequest); delete noAccountBidderRequest.bids[0].params.accountId; @@ -310,11 +292,9 @@ describe('the rubicon adapter', () => { expect(bidManager.addBidResponse.calledOnce).to.equal(true); expect(bids).to.be.lengthOf(1); expect(bids[0].getStatusCode()).to.equal(CONSTANTS.STATUS.NO_BID); - }); it('should allow a floor override', () => { - var floorBidderRequest = clone(bidderRequest); floorBidderRequest.bids[0].params.floor = 2; @@ -323,13 +303,127 @@ describe('the rubicon adapter', () => { let query = parseQuery(xhr.requests[0].url.split('?')[1]); expect(query['rp_floor']).to.equal('2'); + }); + + it('should send digitrust params', () => { + window.DigiTrust = { + getUser: function() {} + }; + sandbox.stub(window.DigiTrust, 'getUser', () => + ({ + success: true, + identity: { + privacy: {optout: false}, + id: 'testId', + keyv: 'testKeyV' + } + }) + ); + + rubiconAdapter.callBids(bidderRequest); + + let request = xhr.requests[0]; + + let query = request.url.split('?')[1]; + query = parseQuery(query); + + let expectedQuery = { + 'dt.id': 'testId', + 'dt.keyv': 'testKeyV', + 'dt.pref': '0' + }; + + // test that all values above are both present and correct + Object.keys(expectedQuery).forEach(key => { + let value = expectedQuery[key]; + expect(query[key]).to.equal(value); + }); + + delete window.DigiTrust; + }); + + it('should not send digitrust params when DigiTrust not loaded', () => { + rubiconAdapter.callBids(bidderRequest); + + let request = xhr.requests[0]; + + let query = request.url.split('?')[1]; + query = parseQuery(query); + + let undefinedKeys = ['dt.id', 'dt.keyv']; + + // Test that none of the DigiTrust keys are part of the query + undefinedKeys.forEach(key => { + expect(typeof query[key]).to.equal('undefined'); + }); + }); + + it('should send not digitrust params due to optout', () => { + window.DigiTrust = { + getUser: function() {} + }; + sandbox.stub(window.DigiTrust, 'getUser', () => + ({ + success: true, + identity: { + privacy: {optout: true}, + id: 'testId', + keyv: 'testKeyV' + } + }) + ); + + rubiconAdapter.callBids(bidderRequest); + + let request = xhr.requests[0]; + + let query = request.url.split('?')[1]; + query = parseQuery(query); + + let undefinedKeys = ['dt.id', 'dt.keyv']; + + // Test that none of the DigiTrust keys are part of the query + undefinedKeys.forEach(key => { + expect(typeof query[key]).to.equal('undefined'); + }); + delete window.DigiTrust; }); + it('should send not digitrust params due to failure', () => { + window.DigiTrust = { + getUser: function() {} + }; + sandbox.stub(window.DigiTrust, 'getUser', () => + ({ + success: false, + identity: { + privacy: {optout: false}, + id: 'testId', + keyv: 'testKeyV' + } + }) + ); + + rubiconAdapter.callBids(bidderRequest); + + let request = xhr.requests[0]; + + let query = request.url.split('?')[1]; + query = parseQuery(query); + + let undefinedKeys = ['dt.id', 'dt.keyv']; + + // Test that none of the DigiTrust keys are part of the query + undefinedKeys.forEach(key => { + expect(typeof query[key]).to.equal('undefined'); + }); + + delete window.DigiTrust; + }); }); describe('for video requests', () => { - /* beforeEach(() => { createVideoBidderRequest(); @@ -380,7 +474,7 @@ describe('the rubicon adapter', () => { expect(slot.site_id).to.equal('70608'); expect(slot.zone_id).to.equal('335918'); expect(slot.position).to.equal('atf'); - expect(slot.floor).to.equal(.01); + expect(slot.floor).to.equal(0.01); expect(slot.element_id).to.equal(bidderRequest.bids[0].placementCode); expect(slot.name).to.equal(bidderRequest.bids[0].placementCode); expect(slot.language).to.equal('en'); @@ -400,7 +494,6 @@ describe('the rubicon adapter', () => { expect(slot).to.have.property('visitor').that.is.an('object'); expect(slot.visitor).to.have.property('ucat').that.equals('new'); expect(slot.visitor).to.have.property('lastsearch').that.equals('iphone'); - }); it('should allow a floor price override', () => { @@ -423,7 +516,6 @@ describe('the rubicon adapter', () => { let floor = post.slots[0].floor; expect(floor).to.equal(3.25); - }); it('should trap when no video object is passed in', () => { @@ -455,18 +547,13 @@ describe('the rubicon adapter', () => { expect(post.slots[0].width).to.equal(300); expect(post.slots[0].height).to.equal(250); }); - }); - }); - - - describe('response handler', () => { let bids, - server, - addBidResponseAction; + server, + addBidResponseAction; beforeEach(() => { bids = []; @@ -475,7 +562,7 @@ describe('the rubicon adapter', () => { sandbox.stub(bidManager, 'addBidResponse', (elemId, bid) => { bids.push(bid); - if(addBidResponseAction) { + if (addBidResponseAction) { addBidResponseAction(); addBidResponseAction = undefined; } @@ -487,9 +574,7 @@ describe('the rubicon adapter', () => { }); describe('for fastlane', () => { - it('should handle a success response and sort by cpm', () => { - server.respondWith(JSON.stringify({ 'status': 'ok', 'account_id': 14062, @@ -591,10 +676,10 @@ describe('the rubicon adapter', () => { 'tracking': '', 'inventory': {}, 'ads': [{ - 'status': 'ok', - 'cpm': 0, - 'size_id': 15 - }] + 'status': 'ok', + 'cpm': 0, + 'size_id': 15 + }] })); rubiconAdapter.callBids(bidderRequest); @@ -643,8 +728,8 @@ describe('the rubicon adapter', () => { 'tracking': '', 'inventory': {}, 'ads': [{ - 'status': 'not_ok', - }] + 'status': 'not_ok', + }] })); rubiconAdapter.callBids(bidderRequest); @@ -669,7 +754,7 @@ describe('the rubicon adapter', () => { }); it('should handle error contacting endpoint', () => { - server.respondWith([404, {}, ""]); + server.respondWith([404, {}, '']); rubiconAdapter.callBids(bidderRequest); @@ -681,7 +766,6 @@ describe('the rubicon adapter', () => { }); it('should not register an error bid when a success call to addBidResponse throws an error', () => { - server.respondWith(JSON.stringify({ 'status': 'ok', 'account_id': 14062, @@ -694,10 +778,10 @@ describe('the rubicon adapter', () => { 'tracking': '', 'inventory': {}, 'ads': [{ - 'status': 'ok', - 'cpm': .8, - 'size_id': 15 - }] + 'status': 'ok', + 'cpm': 0.8, + 'size_id': 15 + }] })); addBidResponseAction = function() { @@ -711,19 +795,15 @@ describe('the rubicon adapter', () => { // was calling twice for same bid, but should only call once expect(bidManager.addBidResponse.calledOnce).to.equal(true); expect(bids).to.be.lengthOf(1); - }); - }); describe('for video', () => { - beforeEach(() => { createVideoBidderRequest(); }); it('should register a successful bid', () => { - server.respondWith(JSON.stringify({ 'status': 'ok', 'ads': { @@ -765,19 +845,13 @@ describe('the rubicon adapter', () => { expect(bids[0].cpm).to.equal(1); expect(bids[0].descriptionUrl).to.equal('a40fe16e-d08d-46a9-869d-2e1573599e0c'); expect(bids[0].vastUrl).to.equal( - 'https://fastlane-adv.rubiconproject.com/v1/creative/a40fe16e-d08d-46a9-869d-2e1573599e0c.xml' + 'https://fastlane-adv.rubiconproject.com/v1/creative/a40fe16e-d08d-46a9-869d-2e1573599e0c.xml' ); expect(bids[0].impression_id).to.equal('a40fe16e-d08d-46a9-869d-2e1573599e0c'); - }); - }); - }); - - }); - }); function clone(obj) { diff --git a/test/spec/modules/sekindoUMBidAdapter_spec.js b/test/spec/modules/sekindoUMBidAdapter_spec.js new file mode 100644 index 00000000000..074e51b3a9d --- /dev/null +++ b/test/spec/modules/sekindoUMBidAdapter_spec.js @@ -0,0 +1,78 @@ +import {expect} from 'chai'; +import sekindoUMAdapter from '../../../modules/sekindoUMBidAdapter'; +var bidManager = require('src/bidmanager'); + +describe('sekindoUM Adapter Tests', () => { + let _sekindoUMAdapter; + var addBidResponseSpy; + + const bidderRequest = { + bidderCode: 'sekindoUM', + bids: [{ + bidder: 'sekindoUM', + bidId: 'sekindo_bidId', + bidderRequestId: 'sekindo_bidderRequestId', + requestId: 'sekindo_requestId', + placementCode: 'foo', + params: { + spaceId: 14071 + } + }] + }; + + beforeEach(() => { + _sekindoUMAdapter = new sekindoUMAdapter(); + }); + + describe('sekindoUM callBids', () => { + beforeEach(() => { + _sekindoUMAdapter.callBids(bidderRequest); + }); + + it('Verify sekindo script tag was created', () => { + var scriptTags = document.getElementsByTagName('script'); + var sekindoTagExists = 0; + for (var i = 0; i < scriptTags.length; i++) { + if (scriptTags[i].src.match('hb.sekindo.com') != null) { + sekindoTagExists = 1; + break; + } + } + expect(sekindoTagExists).to.equal(1); + }); + }); + + describe('Should submit bid responses correctly', function () { + beforeEach(function () { + addBidResponseSpy = sinon.stub(bidManager, 'addBidResponse'); + $$PREBID_GLOBAL$$._bidsRequested.push(bidderRequest); + _sekindoUMAdapter = new sekindoUMAdapter(); + }); + + afterEach(function () { + addBidResponseSpy.restore(); + }); + + it('Should correctly submit valid bid to the bid manager', function () { + var HB_bid = { + adId: 'sekindoUM_bidId', + cpm: 0.23, + width: 300, + height: 250, + ad: '

test ad

' + }; + + $$PREBID_GLOBAL$$.sekindoCB(bidderRequest.bids[0].bidId, HB_bid); + var firstBid = addBidResponseSpy.getCall(0).args[1]; + var placementCode1 = addBidResponseSpy.getCall(0).args[0]; + + expect(firstBid.getStatusCode()).to.equal(1); + expect(firstBid.bidderCode).to.equal('sekindoUM'); + expect(firstBid.cpm).to.equal(0.23); + expect(firstBid.ad).to.equal('

test ad

'); + expect(placementCode1).to.equal('foo'); + + expect(addBidResponseSpy.getCalls().length).to.equal(1); + }); + }); +}); diff --git a/test/spec/adapters/serverbid_spec.js b/test/spec/modules/serverbidBidAdapter_spec.js similarity index 65% rename from test/spec/adapters/serverbid_spec.js rename to test/spec/modules/serverbidBidAdapter_spec.js index 3a7408c34e5..ed1a227235f 100644 --- a/test/spec/adapters/serverbid_spec.js +++ b/test/spec/modules/serverbidBidAdapter_spec.js @@ -1,85 +1,79 @@ -/* jshint -W024 */ -/* jshint expr:true */ - import { expect } from 'chai'; -import Adapter from 'src/adapters/serverbid'; +import Adapter from 'modules/serverbidBidAdapter'; import bidmanager from 'src/bidmanager'; import * as utils from 'src/utils'; const ENDPOINT = '//e.serverbid.com/api/v2'; const REQUEST = { - "bidderCode": "serverbid", - "requestId": "a4713c32-3762-4798-b342-4ab810ca770d", - "bidderRequestId": "109f2a181342a9", - "bids": [{ - "bidder": "serverbid", - "params": { - "networkId": 9969, - "siteId": 730181 + 'bidderCode': 'serverbid', + 'requestId': 'a4713c32-3762-4798-b342-4ab810ca770d', + 'bidderRequestId': '109f2a181342a9', + 'bids': [{ + 'bidder': 'serverbid', + 'params': { + 'networkId': 9969, + 'siteId': 730181 }, - "placementCode": "div-gpt-ad-1487778092495-0", - "sizes": [ + 'placementCode': 'div-gpt-ad-1487778092495-0', + 'sizes': [ [728, 90], [970, 90] ], - "bidId": "2b0f82502298c9", - "bidderRequestId": "109f2a181342a9", - "requestId": "a4713c32-3762-4798-b342-4ab810ca770d" + 'bidId': '2b0f82502298c9', + 'bidderRequestId': '109f2a181342a9', + 'requestId': 'a4713c32-3762-4798-b342-4ab810ca770d' }], - "start": 1487883186070, - "auctionStart": 1487883186069, - "timeout": 3000 + 'start': 1487883186070, + 'auctionStart': 1487883186069, + 'timeout': 3000 }; const RESPONSE = { - "user": { "key": "ue1-2d33e91b71e74929b4aeecc23f4376f1" }, - "decisions": { - "2b0f82502298c9": { - "adId": 2364764, - "creativeId": 1950991, - "flightId": 2788300, - "campaignId": 542982, - "clickUrl": "http://e.serverbid.com/r", - "impressionUrl": "http://e.serverbid.com/i.gif", - "contents": [{ - "type": "html", - "body": "", - "data": { - "height": 90, - "width": 728, - "imageUrl": "http://static.adzerk.net/Advertisers/b0ab77db8a7848c8b78931aed022a5ef.gif", - "fileName": "b0ab77db8a7848c8b78931aed022a5ef.gif" + 'user': { 'key': 'ue1-2d33e91b71e74929b4aeecc23f4376f1' }, + 'decisions': { + '2b0f82502298c9': { + 'adId': 2364764, + 'creativeId': 1950991, + 'flightId': 2788300, + 'campaignId': 542982, + 'clickUrl': 'http://e.serverbid.com/r', + 'impressionUrl': 'http://e.serverbid.com/i.gif', + 'contents': [{ + 'type': 'html', + 'body': '', + 'data': { + 'height': 90, + 'width': 728, + 'imageUrl': 'http://static.adzerk.net/Advertisers/b0ab77db8a7848c8b78931aed022a5ef.gif', + 'fileName': 'b0ab77db8a7848c8b78931aed022a5ef.gif' }, - "template": "image" + 'template': 'image' }], - "height": 90, - "width": 728, - "events": [], - "pricing":{"price":0.5,"clearPrice":0.5,"revenue":0.0005,"rateType":2,"eCPM":0.5} + 'height': 90, + 'width': 728, + 'events': [], + 'pricing': {'price': 0.5, 'clearPrice': 0.5, 'revenue': 0.0005, 'rateType': 2, 'eCPM': 0.5} }, } }; describe('serverbidAdapter', () => { - let adapter; beforeEach(() => adapter = Adapter.createNew()); describe('request function', () => { - let xhr; let requests; let pbConfig; - beforeEach(() => { xhr = sinon.useFakeXMLHttpRequest(); requests = []; xhr.onCreate = request => requests.push(request); pbConfig = REQUEST; - //just a single slot + // just a single slot pbConfig.bids = [pbConfig.bids[0]]; }); @@ -96,11 +90,11 @@ describe('serverbidAdapter', () => { it('requires networkId and siteId', () => { let backup = pbConfig.bids[0].params; - pbConfig.bids[0].params = { networkId: 1234 }; //no hbid + pbConfig.bids[0].params = { networkId: 1234 }; // no hbid adapter.callBids(pbConfig); expect(requests).to.be.empty; - pbConfig.bids[0].params = { siteId: 1234 }; //no placementid + pbConfig.bids[0].params = { siteId: 1234 }; // no placementid adapter.callBids(pbConfig); expect(requests).to.be.empty; @@ -115,13 +109,12 @@ describe('serverbidAdapter', () => { }); describe('response handler', () => { - let server; beforeEach(() => { server = sinon.fakeServer.create(); sinon.stub(bidmanager, 'addBidResponse'); - sinon.stub(utils, "getBidRequest").returns(REQUEST); + sinon.stub(utils, 'getBidRequest').returns(REQUEST); }); afterEach(() => { @@ -145,7 +138,7 @@ describe('serverbidAdapter', () => { it('handles nobid responses', () => { server.respondWith(JSON.stringify({ - "decisions": [] + 'decisions': [] })); adapter.callBids(REQUEST); @@ -172,7 +165,5 @@ describe('serverbidAdapter', () => { 'Bid returned empty or error response' ); }); - }); - -}); \ No newline at end of file +}); diff --git a/test/spec/modules/sharethroughAnalyticsAdapter_spec.js b/test/spec/modules/sharethroughAnalyticsAdapter_spec.js new file mode 100644 index 00000000000..8968e0461fb --- /dev/null +++ b/test/spec/modules/sharethroughAnalyticsAdapter_spec.js @@ -0,0 +1,90 @@ +import sharethroughAnalytics from 'modules/sharethroughAnalyticsAdapter'; +import { expect } from 'chai'; + +describe('sharethrough analytics adapter', () => { + let sandbox; + + beforeEach(() => { + sandbox = sinon.sandbox.create(); + }); + + afterEach(() => { + sandbox.restore(); + }); + + describe('track', () => { + describe('when event type is bidRequested', () => { + beforeEach(() => { + let eventType = 'bidRequested'; + let args = {'bidderCode': 'sharethrough', 'bids': {'0': {'placementCode': 'fake placement Code'}}}; + sharethroughAnalytics.track({eventType, args}) + }); + + it('placementCodeSet contains a value', () => { + expect(sharethroughAnalytics.placementCodeSet['fake placement Code'] == undefined).to.equal(false) + }); + }); + }); + + describe('bid won handler', () => { + let fireLoseBeaconStub; + + beforeEach(() => { + fireLoseBeaconStub = sandbox.stub(sharethroughAnalytics, 'fireLoseBeacon'); + }); + + describe('when bidderCode is not sharethrough and sharethrough is in bid', () => { + beforeEach(() => { + sharethroughAnalytics.placementCodeSet['div-gpt-ad-1460505748561-0'] = {'adserverRequestId': '0eca470d-fcac-48e6-845a-c86483ccaa0c'} + var args = { + 'bidderCode': 'someoneelse', + 'width': 600, + 'height': 300, + 'statusMessage': 'Bid available', + 'adId': '23fbe93a90c924', + 'cpm': 3.984986853301525, + 'adserverRequestId': '0eca470d-fcac-48e6-845a-c86483ccaa0c', + 'winId': '1c404469-f7bb-4e50-b6f6-a8eaf0808999', + 'pkey': 'xKcxTTHyndFyVx7T8GKSzxPE', + 'ad': '
', + 'requestId': 'dd2420bd-cdc2-4c66-8479-f3499ece73da', + 'responseTimestamp': 1473983655565, + 'requestTimestamp': 1473983655458, + 'bidder': 'sharethrough', + 'adUnitCode': 'div-gpt-ad-1460505748561-0', + 'timeToRespond': 107, + 'pbLg': '3.50', + 'pbMg': '3.90', + 'pbHg': '3.98', + 'pbAg': '3.95', + 'pbDg': '3.95', + 'size': '600x300', + 'adserverTargeting': { + 'hb_bidder': 'sharethrough', + 'hb_adid': '23fbe93a90c924', + 'hb_pb': '3.90', + 'hb_size': '600x300' + } + }; + + sharethroughAnalytics.bidWon(args); + }); + + it('should fire lose beacon', () => { + sinon.assert.calledOnce(fireLoseBeaconStub); + }); + }); + }); + + describe('lose beacon is fired', () => { + beforeEach(() => { + sandbox.stub(sharethroughAnalytics, 'fireBeacon'); + sharethroughAnalytics.fireLoseBeacon('someoneelse', 10.0, 'arid', 'losebeacontype'); + }); + + it('should call correct url', () => { + let winUrl = sharethroughAnalytics.fireBeacon.firstCall.args[0]; + expect(winUrl).to.contain(sharethroughAnalytics.STR_BEACON_HOST + 'winnerBidderCode=someoneelse&winnerCpm=10&arid=arid&type=losebeacontype&hbVersion=%24prebid.version%24&strVersion=0.1.0&hbSource=prebid&'); + }); + }); +}); diff --git a/test/spec/adapters/sharethrough_spec.js b/test/spec/modules/sharethroughBidAdapter_spec.js similarity index 71% rename from test/spec/adapters/sharethrough_spec.js rename to test/spec/modules/sharethroughBidAdapter_spec.js index 24884b87ffb..070f20958bb 100644 --- a/test/spec/adapters/sharethrough_spec.js +++ b/test/spec/modules/sharethroughBidAdapter_spec.js @@ -1,9 +1,8 @@ import { expect } from 'chai'; -import Adapter from '../../../src/adapters/sharethrough'; +import Adapter from '../../../modules/sharethroughBidAdapter'; import bidManager from '../../../src/bidmanager'; describe('sharethrough adapter', () => { - let adapter; let sandbox; let bidsRequestedOriginal; @@ -14,7 +13,7 @@ describe('sharethrough adapter', () => { { bidder: 'sharethrough', bidId: 'bidId1', - sizes: [[600,300]], + sizes: [[600, 300]], placementCode: 'foo', params: { pkey: 'aaaa1111' @@ -23,7 +22,7 @@ describe('sharethrough adapter', () => { { bidder: 'sharethrough', bidId: 'bidId2', - sizes: [[700,400]], + sizes: [[700, 400]], placementCode: 'bar', params: { pkey: 'bbbb2222' @@ -35,27 +34,25 @@ describe('sharethrough adapter', () => { beforeEach(() => { adapter = new Adapter(); sandbox = sinon.sandbox.create(); - bidsRequestedOriginal = pbjs._bidsRequested; - pbjs._bidsRequested = []; + bidsRequestedOriginal = $$PREBID_GLOBAL$$._bidsRequested; + $$PREBID_GLOBAL$$._bidsRequested = []; }); afterEach(() => { sandbox.restore(); - pbjs._bidsRequested = bidsRequestedOriginal; + $$PREBID_GLOBAL$$._bidsRequested = bidsRequestedOriginal; }); describe('callBids', () => { - let firstBidUrl; let secondBidUrl; beforeEach(() => { - sandbox.spy(adapter.str, 'ajax'); + sandbox.spy(adapter.str, 'ajax'); }); it('should call ajax to make a request for each bid', () => { - adapter.callBids(bidderRequest); firstBidUrl = adapter.str.ajax.firstCall.args[0]; @@ -66,11 +63,9 @@ describe('sharethrough adapter', () => { expect(firstBidUrl).to.contain(adapter.str.STR_BTLR_HOST + '/header-bid/v1?bidId=bidId1&placement_key=aaaa1111&hbVersion=%24prebid.version%24&strVersion=1.2.0&hbSource=prebid&'); expect(secondBidUrl).to.contain(adapter.str.STR_BTLR_HOST + '/header-bid/v1?bidId=bidId2&placement_key=bbbb2222&hbVersion=%24prebid.version%24&strVersion=1.2.0&hbSource=prebid&'); }); - }); describe('bid requests', () => { - let firstBid; let secondBid; let server; @@ -79,39 +74,39 @@ describe('sharethrough adapter', () => { sandbox.stub(bidManager, 'addBidResponse'); server = sinon.fakeServer.create(); - pbjs._bidsRequested.push(bidderRequest); + $$PREBID_GLOBAL$$._bidsRequested.push(bidderRequest); adapter.str.placementCodeSet['foo'] = {}; adapter.str.placementCodeSet['bar'] = {}; // respond let bidderResponse1 = { - "adserverRequestId": "40b6afd5-6134-4fbb-850a-bb8972a46994", - "bidId": "bidId1", - "creatives": [ - { - "cpm": 12.34, - "auctionWinId": "b2882d5e-bf8b-44da-a91c-0c11287b8051", - "version": 1 - } - ], - "stxUserId": "" - }; + 'adserverRequestId': '40b6afd5-6134-4fbb-850a-bb8972a46994', + 'bidId': 'bidId1', + 'creatives': [ + { + 'cpm': 12.34, + 'auctionWinId': 'b2882d5e-bf8b-44da-a91c-0c11287b8051', + 'version': 1 + } + ], + 'stxUserId': '' + }; let bidderResponse2 = { - "adserverRequestId": "40b6afd5-6134-4fbb-850a-bb8972a46994", - "bidId": "bidId2", - "creatives": [ - { - "cpm": 12.35, - "auctionWinId": "b2882d5e-bf8b-44da-a91c-0c11287b8051", - "version": 1 - } - ], - "stxUserId": "" - }; - - server.respondWith(/aaaa1111/,JSON.stringify(bidderResponse1)); - server.respondWith(/bbbb2222/,JSON.stringify(bidderResponse2)); + 'adserverRequestId': '40b6afd5-6134-4fbb-850a-bb8972a46994', + 'bidId': 'bidId2', + 'creatives': [ + { + 'cpm': 12.35, + 'auctionWinId': 'b2882d5e-bf8b-44da-a91c-0c11287b8051', + 'version': 1 + } + ], + 'stxUserId': '' + }; + + server.respondWith(/aaaa1111/, JSON.stringify(bidderResponse1)); + server.respondWith(/bbbb2222/, JSON.stringify(bidderResponse2)); adapter.callBids(bidderRequest); server.respond(); @@ -172,7 +167,5 @@ describe('sharethrough adapter', () => { expect(firstBid).to.have.property('pkey', 'aaaa1111'); expect(secondBid).to.have.property('pkey', 'bbbb2222'); }); - }); - }); diff --git a/test/spec/modules/smartadserverBidAdapter_spec.js b/test/spec/modules/smartadserverBidAdapter_spec.js new file mode 100644 index 00000000000..85d345da368 --- /dev/null +++ b/test/spec/modules/smartadserverBidAdapter_spec.js @@ -0,0 +1,154 @@ +describe('smartadserver adapter tests', function () { + var urlParse = require('url-parse'); + var querystringify = require('querystringify'); + var adapter = require('modules/smartadserverBidAdapter'); + var adLoader = require('src/adloader'); + var expect = require('chai').expect; + var bidmanager = require('src/bidmanager'); + var CONSTANTS = require('src/constants.json'); + + var DEFAULT_PARAMS = { + bidderCode: 'smartadserver', + bids: [{ + bidId: 'abcd1234', + sizes: [[300, 250], [300, 200]], + bidder: 'smartadserver', + params: { + domain: 'http://www.smartadserver.com', + siteId: '1234', + pageId: '5678', + formatId: '90', + target: 'test=prebid', + currency: 'EUR', + bidfloor: 0.420 + }, + requestId: 'efgh5678', + placementCode: 'sas_42' + } + ] + }; + + var DEFAULT_PARAMS_WO_OPTIONAL = { + bidderCode: 'smartadserver', + bids: [{ + bidId: 'abcd1234', + sizes: [[300, 250], [300, 200]], + bidder: 'smartadserver', + params: { + domain: 'http://www.smartadserver.com', + siteId: '1234', + pageId: '5678', + formatId: '90' + }, + requestId: 'efgh5678', + placementCode: 'sas_42' + } + ] + }; + + var BID_RESPONSE = { + cpm: 0.42, + ad: 'fake ad content', + width: 300, + height: 250 + }; + + it('set url parameters', function () { + var stubLoadScript = sinon.stub(adLoader, 'loadScript'); + + adapter().callBids(DEFAULT_PARAMS); + + var smartCallback; + for (var k in $$PREBID_GLOBAL$$) { + if (k.lastIndexOf('sas_', 0) === 0) { + smartCallback = k; + break; + } + } + + var bidUrl = stubLoadScript.getCall(0).args[0]; + var parsedBidUrl = urlParse(bidUrl); + var parsedBidUrlQueryString = querystringify.parse(parsedBidUrl.query); + + expect(parsedBidUrl.hostname).to.equal('www.smartadserver.com'); + expect(parsedBidUrl.pathname).to.equal('/prebid'); + + expect(parsedBidUrlQueryString).to.have.property('pbjscbk').and.to.equal('pbjs.' + smartCallback); + expect(parsedBidUrlQueryString).to.have.property('siteid').and.to.equal('1234'); + expect(parsedBidUrlQueryString).to.have.property('pgid').and.to.equal('5678'); + expect(parsedBidUrlQueryString).to.have.property('fmtid').and.to.equal('90'); + expect(parsedBidUrlQueryString).to.have.property('tgt').and.to.equal('test=prebid'); + expect(parsedBidUrlQueryString).to.have.property('ccy').and.to.equal('EUR'); + expect(parsedBidUrlQueryString).to.have.property('bidfloor').and.to.equal('0.42'); + expect(parsedBidUrlQueryString).to.have.property('tag').and.to.equal('sas_42'); + expect(parsedBidUrlQueryString).to.have.property('sizes').and.to.equal('300x250,300x200'); + expect(parsedBidUrlQueryString).to.have.property('async').and.to.equal('1'); + + stubLoadScript.restore(); + }); + + it('test optional parameters default value', function () { + var stubLoadScript = sinon.stub(adLoader, 'loadScript'); + + adapter().callBids(DEFAULT_PARAMS_WO_OPTIONAL); + + var bidUrl = stubLoadScript.getCall(0).args[0]; + var parsedBidUrl = urlParse(bidUrl); + var parsedBidUrlQueryString = querystringify.parse(parsedBidUrl.query); + + expect(parsedBidUrlQueryString).to.have.property('tgt').and.to.equal(''); + expect(parsedBidUrlQueryString).to.have.property('ccy').and.to.equal('USD'); + + stubLoadScript.restore(); + }); + + it('creates an empty bid response if no bids', function() { + var stubLoadScript = sinon.stub(adLoader, 'loadScript', function(url) { + var bidUrl = stubLoadScript.getCall(0).args[0]; + var parsedBidUrl = urlParse(bidUrl); + var parsedBidUrlQueryString = querystringify.parse(parsedBidUrl.query); + + pbjs[parsedBidUrlQueryString.pbjscbk.split('.')[1]](null); + }); + var stubAddBidResponse = sinon.stub(bidmanager, 'addBidResponse'); + + adapter().callBids(DEFAULT_PARAMS); + + var bidResponsePlacementCode = stubAddBidResponse.getCall(0).args[0]; + var bidResponseAd = stubAddBidResponse.getCall(0).args[1]; + + expect(bidResponsePlacementCode).to.equal(DEFAULT_PARAMS.bids[0].placementCode); + expect(bidResponseAd.getStatusCode()).to.equal(CONSTANTS.STATUS.NO_BID); + expect(bidResponseAd).to.have.property('bidderCode').and.to.equal('smartadserver'); + + stubLoadScript.restore(); + stubAddBidResponse.restore(); + }); + + it('creates a bid response if bid is returned', function() { + var stubLoadScript = sinon.stub(adLoader, 'loadScript', function(url) { + var bidUrl = stubLoadScript.getCall(0).args[0]; + var parsedBidUrl = urlParse(bidUrl); + var parsedBidUrlQueryString = querystringify.parse(parsedBidUrl.query); + + pbjs[parsedBidUrlQueryString.pbjscbk.split('.')[1]](BID_RESPONSE); + }); + var stubAddBidResponse = sinon.stub(bidmanager, 'addBidResponse'); + + adapter().callBids(DEFAULT_PARAMS); + + var bidResponsePlacementCode = stubAddBidResponse.getCall(0).args[0]; + var bidResponseAd = stubAddBidResponse.getCall(0).args[1]; + + expect(bidResponsePlacementCode).to.equal(DEFAULT_PARAMS.bids[0].placementCode); + expect(bidResponseAd.getStatusCode()).to.equal(CONSTANTS.STATUS.GOOD); + expect(bidResponseAd).to.have.property('bidderCode').and.to.equal('smartadserver'); + expect(bidResponseAd).to.have.property('cpm').and.to.equal(BID_RESPONSE.cpm); + expect(bidResponseAd).to.have.property('ad').and.to.equal(BID_RESPONSE.ad); + expect(bidResponseAd).to.have.property('width').and.to.equal(BID_RESPONSE.width); + expect(bidResponseAd).to.have.property('height').and.to.equal(BID_RESPONSE.height); + + stubLoadScript.restore(); + stubAddBidResponse.restore(); + }); +}); diff --git a/test/spec/modules/smartyadsBidAdapter_spec.js b/test/spec/modules/smartyadsBidAdapter_spec.js new file mode 100644 index 00000000000..d7c723604a6 --- /dev/null +++ b/test/spec/modules/smartyadsBidAdapter_spec.js @@ -0,0 +1,128 @@ +import { expect } from 'chai'; +import Adapter from '../../../modules/smartyadsBidAdapter'; +import adapterManager from 'src/adaptermanager'; +import bidManager from 'src/bidmanager'; +import CONSTANTS from 'src/constants.json'; + +describe('Smartyads adapter tests', function () { + let sandbox; + const adUnit = { // TODO CHANGE + code: 'smartyads', + sizes: [[300, 250], [300, 600], [320, 80]], + bids: [{ + bidder: 'smartyads', + params: { + banner_id: 0 + } + }] + }; + + const response = { + ad_id: 0, + adm: 'Test Response', + cpm: 0.5, + deal: 'bf063e2e025c', + height: 240, + width: 360 + }; + + beforeEach(() => { + sandbox = sinon.sandbox.create(); + }); + + afterEach(() => { + sandbox.restore(); + }); + + describe('Smartyads callBids validation', () => { + let bids, + server; + + beforeEach(() => { + bids = []; + server = sinon.fakeServer.create(); + + sandbox.stub(bidManager, 'addBidResponse', (elemId, bid) => { + bids.push(bid); + }); + }); + + afterEach(() => { + server.restore(); + }); + + let adapter = adapterManager.bidderRegistry['smartyads']; + + it('Valid bid-request', () => { + sandbox.stub(adapter, 'callBids'); + adapterManager.callBids({ + adUnits: [clone(adUnit)] + }); + + let bidderRequest = adapter.callBids.getCall(0).args[0]; + + expect(bidderRequest).to.have.property('bids') + .that.is.an('array') + .with.lengthOf(1); + + expect(bidderRequest).to.have.deep.property('bids[0]') + .to.have.property('bidder', 'smartyads'); + + expect(bidderRequest).to.have.deep.property('bids[0]') + .with.property('sizes') + .that.is.an('array') + .with.lengthOf(3) + .that.deep.equals(adUnit.sizes); + expect(bidderRequest).to.have.deep.property('bids[0]') + .with.property('params') + .to.have.property('banner_id', 0); + }); + + it('Valid bid-response', () => { + server.respondWith(JSON.stringify( + response + )); + adapterManager.callBids({ + adUnits: [clone(adUnit)] + }); + server.respond(); + + expect(bids).to.be.lengthOf(1); + expect(bids[0].getStatusCode()).to.equal(CONSTANTS.STATUS.GOOD); + expect(bids[0].bidderCode).to.equal('smartyads'); + expect(bids[0].width).to.equal(360); + expect(bids[0].height).to.equal(240); + expect(bids[0].cpm).to.equal(0.5); + expect(bids[0].dealId).to.equal('bf063e2e025c'); + }); + }); + + describe('MAS mapping / ordering', () => { + let masSizeOrdering = Adapter.masSizeOrdering; + + it('should not include values without a proper mapping', () => { + let ordering = masSizeOrdering([[320, 50], [42, 42], [300, 250], [640, 480], [1, 1], [336, 280]]); + expect(ordering).to.deep.equal([15, 16, 43, 65]); + }); + + it('should sort values without any MAS priority sizes in regular ascending order', () => { + let ordering = masSizeOrdering([[320, 50], [640, 480], [336, 280], [200, 600]]); + expect(ordering).to.deep.equal([16, 43, 65, 126]); + }); + + it('should sort MAS priority sizes in the proper order w/ rest ascending', () => { + let ordering = masSizeOrdering([[320, 50], [160, 600], [640, 480], [300, 250], [336, 280], [200, 600]]); + expect(ordering).to.deep.equal([15, 9, 16, 43, 65, 126]); + + ordering = masSizeOrdering([[320, 50], [300, 250], [160, 600], [640, 480], [336, 280], [200, 600], [728, 90]]); + expect(ordering).to.deep.equal([15, 2, 9, 16, 43, 65, 126]); + + ordering = masSizeOrdering([[120, 600], [320, 50], [160, 600], [640, 480], [336, 280], [200, 600], [728, 90]]); + expect(ordering).to.deep.equal([2, 9, 8, 16, 43, 65, 126]); + }) + }); +}); + +function clone(obj) { + return JSON.parse(JSON.stringify(obj)); +} diff --git a/test/spec/adapters/sonobi_spec.js b/test/spec/modules/sonobiBidAdapter_spec.js similarity index 80% rename from test/spec/adapters/sonobi_spec.js rename to test/spec/modules/sonobiBidAdapter_spec.js index ca0cd6735ee..346fc18e637 100644 --- a/test/spec/adapters/sonobi_spec.js +++ b/test/spec/modules/sonobiBidAdapter_spec.js @@ -1,6 +1,6 @@ const chai = require('chai'); const expect = require('chai').expect; -const Adapter = require('src/adapters/sonobi'); +const Adapter = require('modules/sonobiBidAdapter'); const bidManager = require('src/bidmanager'); const adLoader = require('src/adloader'); const utils = require('src/utils'); @@ -15,7 +15,7 @@ describe('Sonobi adapter tests', () => { bidId: 'testbid', bidder: 'sonobi', placementCode: 'adUnit_p', - sizes: [[300, 250],[300,600]], + sizes: [[300, 250], [300, 600]], params: { placement_id: '1a2b3c4d5e6f1a2b3c4d' } @@ -27,7 +27,7 @@ describe('Sonobi adapter tests', () => { bidId: 'testbid', bidder: 'sonobi', placementCode: 'adUnit_pd', - sizes: [[300, 250],[300,600]], + sizes: [[300, 250], [300, 600]], params: { placement_id: '1a2b3c4d5e6f1a2b3c4d', dom_id: 'div-gpt-ad-12345-0' @@ -40,7 +40,7 @@ describe('Sonobi adapter tests', () => { bidId: 'testbid', bidder: 'sonobi', placementCode: 'adUnit_pdf', - sizes: [[300, 250],[300,600]], + sizes: [[300, 250], [300, 600]], params: { placement_id: '1a2b3c4d5e6f1a2b3c4d', dom_id: 'div-gpt-ad-12345-0', @@ -54,7 +54,7 @@ describe('Sonobi adapter tests', () => { bidId: 'testbid', bidder: 'sonobi', placementCode: 'adUnit_a', - sizes: [[300, 250],[300,600]], + sizes: [[300, 250], [300, 600]], params: { ad_unit: '/7780971/sparks_prebid_MR', } @@ -79,7 +79,7 @@ describe('Sonobi adapter tests', () => { bidId: 'testbid', bidder: 'sonobi', placementCode: 'adUnit_ad', - sizes: [[300, 250],[300,600]], + sizes: [[300, 250], [300, 600]], params: { ad_unit: '/7780971/sparks_prebid_MR', dom_id: 'div-gpt-ad-12345-0' @@ -92,7 +92,7 @@ describe('Sonobi adapter tests', () => { bidId: 'testbid', bidder: 'sonobi', placementCode: 'adUnit_af', - sizes: [[300, 250],[300,600]], + sizes: [[300, 250], [300, 600]], params: { ad_unit: '/7780971/sparks_prebid_MR', floor: '1' @@ -105,7 +105,7 @@ describe('Sonobi adapter tests', () => { bidId: 'testbid', bidder: 'sonobi', placementCode: 'adUnit_adf', - sizes: [[300, 250],[300,600]], + sizes: [[300, 250], [300, 600]], params: { ad_unit: '/7780971/sparks_prebid_MR', dom_id: 'div-gpt-ad-12345-0', @@ -119,7 +119,7 @@ describe('Sonobi adapter tests', () => { bidId: 'testbid', bidder: 'sonobi', placementCode: 'adUnit_A', - sizes: [[300, 250],[300,600]], + sizes: [[300, 250], [300, 600]], params: { ad_unit: '/7780971/sparks_prebid_MR', } @@ -131,7 +131,7 @@ describe('Sonobi adapter tests', () => { bidId: 'testbid', bidder: 'sonobi', placementCode: 'adUnit_Ad', - sizes: [[300, 250],[300,600]], + sizes: [[300, 250], [300, 600]], params: { ad_unit: '7780971/sparks_prebid_MR', dom_id: 'div-gpt-ad-12345-0' @@ -144,7 +144,7 @@ describe('Sonobi adapter tests', () => { bidId: 'testbid', bidder: 'sonobi', placementCode: 'adUnit_Af', - sizes: [[300, 250],[300,600]], + sizes: [[300, 250], [300, 600]], params: { ad_unit: '7780971/sparks_prebid_MR', floor: '1' @@ -157,7 +157,7 @@ describe('Sonobi adapter tests', () => { bidId: 'testbid', bidder: 'sonobi', placementCode: 'adUnit_Adf', - sizes: [[300, 250],[300,600]], + sizes: [[300, 250], [300, 600]], params: { ad_unit: '7780971/sparks_prebid_MR', dom_id: 'div-gpt-ad-12345-0', @@ -172,7 +172,7 @@ describe('Sonobi adapter tests', () => { bidId: 'testbid', bidder: 'sonobi', placementCode: 'adUnit_m1hb', - sizes: [[300, 250],[300,600]], + sizes: [[300, 250], [300, 600]], params: { ad_unit: '1a2b3c4d5e6f1a2b3c4d', dom_id: 'div-gpt-ad-12345-0' @@ -185,7 +185,7 @@ describe('Sonobi adapter tests', () => { bidId: 'testbid', bidder: 'sonobi', placementCode: 'adUnit_m2hb', - sizes: [[300, 250],[300,600]], + sizes: [[300, 250], [300, 600]], params: { ad_unit: '/7780971/sparks_prebid_MR', placement_id: 'OPTIONAL', @@ -199,7 +199,7 @@ describe('Sonobi adapter tests', () => { bidId: 'testbid', bidder: 'sonobi', placementCode: 'adUnit_m3hb', - sizes: [[300, 250],[300,600]], + sizes: [[300, 250], [300, 600]], params: { ad_unit: '/7780971/sparks_prebid_MR', placement_id: '', @@ -213,7 +213,7 @@ describe('Sonobi adapter tests', () => { bidId: 'testbid', bidder: 'sonobi', placementCode: 'adUnit_m4hb', - sizes: [[300, 250],[300,600]], + sizes: [[300, 250], [300, 600]], params: { ad_unit: '', placement_id: '1a2b3c4d5e6f1a2b3c4d', @@ -227,7 +227,7 @@ describe('Sonobi adapter tests', () => { bidId: 'testbid', bidder: 'sonobi', placementCode: 'adUnit_m5hb', - sizes: [[300, 250],[300,600]], + sizes: [[300, 250], [300, 600]], params: { placement_id: '/7780971/sparks_prebid_MR', dom_id: 'div-gpt-ad-12345-0' @@ -236,29 +236,28 @@ describe('Sonobi adapter tests', () => { }; // FTFY const sbi_adUnits = { - 'adUnit_p' : adUnit_p, - 'adUnit_pd' : adUnit_pd, - 'adUnit_pdf' : adUnit_pdf, - 'adUnit_a' : adUnit_a, - 'adUnit_as' : adUnit_as, - 'adUnit_ad' : adUnit_ad, - 'adUnit_af' : adUnit_af, - 'adUnit_adf' : adUnit_adf, - 'adUnit_A' : adUnit_A, - 'adUnit_Ad' : adUnit_Ad, - 'adUnit_Af' : adUnit_Af, - 'adUnit_Adf' : adUnit_Adf, - 'adUnit_m1hb' : adUnit_m1hb, - 'adUnit_m2hb' : adUnit_m2hb, - 'adUnit_m3hb' : adUnit_m3hb, - 'adUnit_m4hb' : adUnit_m4hb, - 'adUnit_m5hb' : adUnit_m5hb + 'adUnit_p': adUnit_p, + 'adUnit_pd': adUnit_pd, + 'adUnit_pdf': adUnit_pdf, + 'adUnit_a': adUnit_a, + 'adUnit_as': adUnit_as, + 'adUnit_ad': adUnit_ad, + 'adUnit_af': adUnit_af, + 'adUnit_adf': adUnit_adf, + 'adUnit_A': adUnit_A, + 'adUnit_Ad': adUnit_Ad, + 'adUnit_Af': adUnit_Af, + 'adUnit_Adf': adUnit_Adf, + 'adUnit_m1hb': adUnit_m1hb, + 'adUnit_m2hb': adUnit_m2hb, + 'adUnit_m3hb': adUnit_m3hb, + 'adUnit_m4hb': adUnit_m4hb, + 'adUnit_m5hb': adUnit_m5hb }; // Run the same test against all the (now tons of) different configurations utils._each(sbi_adUnits, (adUnit, adUnitName) => { describe('should form valid bid requests', () => { - let adapter = new Adapter(); let stubLoadScript; let stubFailBid; @@ -291,71 +290,68 @@ describe('Sonobi adapter tests', () => { expect(stubLoadScript.callCount).to.equal(1); expect(stubFailBid.callCount).to.equal(0); }); - }); - }); describe('should parse bid returns and register bid objects', () => { - let adapter = new Adapter(); let spyAddBidResponse; let stubFailBid; let stubGoodBid; const sbi_bid = { - "slots": + 'slots': { - "sbi_a": + 'sbi_a': { - "sbi_size": "300x250", - "sbi_apoc": "premium", - "sbi_aid": "159.60.7533347", - "sbi_mouse": 4.20 + 'sbi_size': '300x250', + 'sbi_apoc': 'premium', + 'sbi_aid': '159.60.7533347', + 'sbi_mouse': 4.20 } }, - "sbi_dc": "mco-1-" + 'sbi_dc': 'mco-1-' }; const sbi_video_bid = { - "slots": + 'slots': { - "sbi_a": + 'sbi_a': { - "sbi_size": "outstream", - "sbi_apoc": "premium", - "sbi_aid": "159.60.7533347", - "sbi_mouse": 4.20, + 'sbi_size': 'outstream', + 'sbi_apoc': 'premium', + 'sbi_aid': '159.60.7533347', + 'sbi_mouse': 4.20, } }, - "sbi_dc": "mco-1-" + 'sbi_dc': 'mco-1-' }; const sbi_deal_bid = { - "slots": + 'slots': { - "sbi_a": + 'sbi_a': { - "sbi_size": "300x250", - "sbi_apoc": "premium", - "sbi_aid": "159.60.7533347", - "sbi_mouse": 4.20, - "sbi_dozer": "apex-test-deal" + 'sbi_size': '300x250', + 'sbi_apoc': 'premium', + 'sbi_aid': '159.60.7533347', + 'sbi_mouse': 4.20, + 'sbi_dozer': 'apex-test-deal' } }, - "sbi_dc": "mco-1-" + 'sbi_dc': 'mco-1-' }; const sbi_noBid = { - "slots": + 'slots': { - "sbi_a": {} + 'sbi_a': {} }, - "sbi_dc": "mco-1-" + 'sbi_dc': 'mco-1-' }; beforeEach(() => { - spyAddBidResponse = sinon.spy(bidManager, "addBidResponse"); + spyAddBidResponse = sinon.spy(bidManager, 'addBidResponse'); stubFailBid = sinon.stub(adapter, 'failure'); stubGoodBid = sinon.stub(adapter, 'success'); }); @@ -389,8 +385,5 @@ describe('Sonobi adapter tests', () => { expect(spyAddBidResponse.called).to.be.true; expect(stubGoodBid.callCount).to.equal(0); }); - }); - - -}); \ No newline at end of file +}); diff --git a/test/spec/adapters/sovrn_spec.js b/test/spec/modules/sovrnBidAdapter_spec.js similarity index 87% rename from test/spec/adapters/sovrn_spec.js rename to test/spec/modules/sovrnBidAdapter_spec.js index 2ffed6f6774..e0be789c1bf 100644 --- a/test/spec/adapters/sovrn_spec.js +++ b/test/spec/modules/sovrnBidAdapter_spec.js @@ -1,12 +1,11 @@ describe('sovrn adapter tests', function () { const expect = require('chai').expect; - const adapter = require('src/adapters/sovrn'); + const adapter = require('modules/sovrnBidAdapter'); const bidmanager = require('src/bidmanager'); describe('sovrnResponse', function () { - it('should exist and be a function', function () { - expect(pbjs.sovrnResponse).to.exist.and.to.be.a('function'); + expect($$PREBID_GLOBAL$$.sovrnResponse).to.exist.and.to.be.a('function'); }); it('should add empty bid responses if no bids returned', function () { @@ -47,15 +46,15 @@ describe('sovrn adapter tests', function () { // no bids returned in the response. var response = { - "id": "54321", - "seatbid": [] + 'id': '54321', + 'seatbid': [] }; - pbjs._bidsRequested.push(bidderRequest); + $$PREBID_GLOBAL$$._bidsRequested.push(bidderRequest); // adapter needs to be called, in order for the stub to register. adapter() - pbjs.sovrnResponse(response); + $$PREBID_GLOBAL$$.sovrnResponse(response); var bidPlacementCode1 = stubAddBidResponse.getCall(0).args[0]; var bidObject1 = stubAddBidResponse.getCall(0).args[1]; @@ -119,26 +118,26 @@ describe('sovrn adapter tests', function () { // Returning a single bid in the response. var response = { - "id": "54321111", - "seatbid": [ { - "bid" : [ { - "id" : "1111111", - "impid" : "bidId2", - "price" : 0.09, - "nurl" : "http://url", - "adm" : "ad-code", - "h" : 250, - "w" : 300, - "ext" : { } + 'id': '54321111', + 'seatbid': [ { + 'bid': [ { + 'id': '1111111', + 'impid': 'bidId2', + 'price': 0.09, + 'nurl': 'http://url', + 'adm': 'ad-code', + 'h': 250, + 'w': 300, + 'ext': { } } ] } ] }; - pbjs._bidsRequested.push(bidderRequest); + $$PREBID_GLOBAL$$._bidsRequested.push(bidderRequest); // adapter needs to be called, in order for the stub to register. adapter() - pbjs.sovrnResponse(response); + $$PREBID_GLOBAL$$.sovrnResponse(response); var bidPlacementCode1 = stubAddBidResponse.getCall(0).args[0]; var bidObject1 = stubAddBidResponse.getCall(0).args[1]; @@ -171,4 +170,3 @@ describe('sovrn adapter tests', function () { }); }); }); - diff --git a/test/spec/modules/spotxBidAdapter_spec.js b/test/spec/modules/spotxBidAdapter_spec.js new file mode 100644 index 00000000000..e78e4c7c6ee --- /dev/null +++ b/test/spec/modules/spotxBidAdapter_spec.js @@ -0,0 +1,227 @@ +import {expect} from 'chai'; +import {assert} from 'chai'; +import Adapter from 'modules/spotxBidAdapter'; +import bidManager from 'src/bidmanager'; +import adLoader from 'src/adloader'; + +const CHANNEL_ID = 85394; +const CACHE_KEY = 'eyJob3N0IjoiZmUwMDEuc3BvdHguZ2FkZ2V0cy5sb2QiLCJja'; + +let bidRequest = { + 'bidderCode': 'spotx', + 'requestId': '4b8bb067-fca9-478b-9207-d24b87fce85c', + 'bidderRequestId': '1bfc89fa86fd1d', + 'timeout': 1000, + 'bids': [ + { + 'bidId': '2626663210bd26', + 'bidder': 'spotx', + 'bidderRequestId': '145a190a61161e', + 'mediaType': 'video', + 'params': { + 'placementId': '123456789', + 'video': { + 'ad_mute': false, + 'autoplay': true, + 'channel_id': CHANNEL_ID, + 'hide_skin': false, + 'slot': null, + 'video_slot': null + } + }, + 'placementCode': 'video1', + 'requestId': '5e1e93aa-55cf-4f73-a56a-8a74d0584c5f', + 'sizes': [[640, 480]], + 'transactionId': 'df629792-c9ae-481e-9ce1-eaa83bde4cdb' + } + ] +}; + +let badBidRequest = { + 'bidderCode': 'spotx', + 'bids': [ + { + 'bidId': '2626663210bd26', + 'bidder': 'spotx', + 'mediaType': 'video', + 'params': { + 'placementId': '123456789', + 'video': { + 'slot': 'contentSpotx', + 'video_slot': 'contentElementSpotx' + } + }, + 'placementCode': 'video1', + } + ] +}; + +var xhrResponse = JSON.stringify({ + 'id': CHANNEL_ID.toString(), + 'cur': 'USD', + 'seatbid': [ + { + 'bid': [ + { + 'id': '47e.fc9b5.90ede6', + 'impid': '1497549328279', + 'impression_guid': 'e2514a4651f311e7b50f113c04e90000', + 'price': '20', + 'adm': '<\/VASTAdTagURI><\/Wrapper><\/Ad><\/VAST>', + 'adomain': 'null', + 'crid': '47e.fc9b5.90ede6', + 'cid': 'null', + 'ext': { + 'cache_key': CACHE_KEY + } + } + ] + } + ] +}); + +describe('spotx adapter tests', () => { + describe('callBids', () => { + let server; + let adapter; + + beforeEach(() => { + adapter = Adapter.createNew(); + + var slot = document.createElement('div'); + slot.setAttribute('id', 'contentSpotx'); + document.body.appendChild(slot); + + var videoSlot = document.createElement('video'); + videoSlot.setAttribute('id', 'contentElementSpotx'); + slot.appendChild(videoSlot); + + var source1 = document.createElement('source'); + source1.setAttribute('src', 'http://rmcdn.2mdn.net/Demo/vast_inspector/android.mp4'); + videoSlot.appendChild(source1); + + bidRequest.bids[0].params.video.slot = slot; + bidRequest.bids[0].params.video.video_slot = videoSlot; + + server = sinon.fakeServer.create(); + server.respondImmediately = true; + }); + + afterEach(() => { + var slot = document.getElementById('contentSpotx'); + while (slot.firstChild) { + slot.removeChild(slot.firstChild); + } + var body = slot.parentElement; + body.removeChild(slot); + + server.restore(); + }); + + it('should load Direct AdOS onto page', () => { + sinon.spy(adLoader, 'loadScript'); + + adapter.callBids(bidRequest); + + sinon.assert.calledOnce(adLoader.loadScript); + expect(adLoader.loadScript.firstCall.args[0]).to.equal('//js.spotx.tv/directsdk/v1/' + CHANNEL_ID + '.js'); + expect(adLoader.loadScript.firstCall.args[1]).to.be.a('function'); + + adLoader.loadScript.restore(); + }); + + it('should not load Direct AdOS onto page if no bid is provided', () => { + sinon.spy(adLoader, 'loadScript'); + + adapter.callBids(); + sinon.assert.notCalled(adLoader.loadScript); + adLoader.loadScript.restore(); + }); + + describe('bid response tests', () => { + let loadScriptStub; + let getAdServerKVPsStub; + + before(() => { + let response = { + spotx_bid: 20, + spotx_ad_key: CACHE_KEY + }; + + getAdServerKVPsStub = sinon.stub(); + getAdServerKVPsStub.onCall(0).returns({ + then: function (successCb) { + return successCb(response); + } + }); + + getAdServerKVPsStub.onCall(1).returns({ + then: function (successCb, failureCb) { + return failureCb(); + } + }); + + window.SpotX = { + DirectAdOS: function(options) { + return { + getAdServerKVPs: getAdServerKVPsStub + } + } + }; + + loadScriptStub = sinon.stub(adLoader, 'loadScript', function(url, callback) { + callback(); + }); + }); + + after(() => { + loadScriptStub.restore(); + }); + + it('should add bid response on success', (done) => { + sinon.stub(bidManager, 'addBidResponse', (placementCode, bid) => { + expect(placementCode).to.equal('video1'); + expect(bid.bidderCode).to.equal('spotx'); + expect(bid.cpm).to.equal(20); + expect(bid.mediaType).to.equal('video'); + expect(bid.statusMessage).to.equal('Bid available'); + expect(bid.vastUrl).to.equal('//search.spotxchange.com/ad/vast.html?key=' + CACHE_KEY); + + bidManager.addBidResponse.restore(); + done(); + }); + + server.respondWith((request) => { + if (request.url.match(/openrtb\/2.3\/dados/) && request.method === 'POST') { + request.respond(200, {}, xhrResponse); + } + }); + + adapter.callBids(bidRequest); + }); + + it('should add failed bid response on error', (done) => { + sinon.stub(bidManager, 'addBidResponse', (placementCode, bid) => { + expect(placementCode).to.equal('video1'); + expect(bid.bidderCode).to.equal('spotx'); + expect(bid.statusMessage).to.equal('Bid returned empty or error response'); + expect(bid.cpm).to.be.undefined; + expect(bid.mediaType).to.be.undefined; + expect(bid.vastUrl).to.be.undefined; + + bidManager.addBidResponse.restore(); + done(); + }); + + server.respondWith((request) => { + if (request.url.match(/openrtb\/2.3\/dados/) && request.method === 'POST') { + request.respond(204, {}, ''); + } + }); + + adapter.callBids(bidRequest); + }); + }); + }); +}); diff --git a/test/spec/modules/stickyadstvBidAdapter_spec.js b/test/spec/modules/stickyadstvBidAdapter_spec.js new file mode 100644 index 00000000000..c0f35b1c406 --- /dev/null +++ b/test/spec/modules/stickyadstvBidAdapter_spec.js @@ -0,0 +1,225 @@ +import {expect} from 'chai'; +import {assert} from 'chai'; +import Adapter from '../../../modules/stickyadstvBidAdapter'; +import adLoader from '../../../src/adloader'; + +describe('StickyAdsTV Adapter', function () { + var adapter = void 0; + var sandbox = void 0; + var bidsRequestBuff = void 0; + var bidderRequest = { + bidderCode: 'stickyadstv', + bids: [{ + bidId: 'bidId1', + bidder: 'stickyadstv', + placementCode: 'foo', + sizes: [[300, 250]], + params: { + zoneId: '2003', + format: 'screen-roll' + } + }, { + bidId: 'bidId2', + bidder: 'stickyadstv', + placementCode: 'bar', + sizes: [[728, 90]], + params: { + zoneId: '5562003' + } + }, { + bidId: 'bidId3', + bidder: 'stickyadstv', + placementCode: '', + sizes: [[300, 600]], + params: { + zoneId: '123456' + } + }, { + bidId: 'bidId4', + bidder: 'stickyadstv', + placementCode: 'coo', + sizes: [[300, 600]], + params: { + wrong: 'missing zoneId' + } + }] + }; + + beforeEach(function () { + adapter = new Adapter(); + sandbox = sinon.sandbox.create(); + bidsRequestBuff = $$PREBID_GLOBAL$$._bidsRequested; + $$PREBID_GLOBAL$$._bidsRequested = []; + }); + + afterEach(function () { + sandbox.restore(); + $$PREBID_GLOBAL$$._bidsRequested = bidsRequestBuff; + }); + + describe('callBids', function () { + beforeEach(function () { + sandbox.stub(adLoader, 'loadScript'); + adapter.callBids(bidderRequest); + }); + + it('should be called twice', function () { + sinon.assert.calledTwice(adLoader.loadScript); + }); + + it('should have load screenroll and mustang script', function () { + var url = void 0; + + url = adLoader.loadScript.firstCall.args[0]; + expect(url).to.equal('//cdn.stickyadstv.com/prime-time/screen-roll.min.js'); + + url = adLoader.loadScript.secondCall.args[0]; + expect(url).to.equal('//cdn.stickyadstv.com/mustang/mustang.min.js'); + }); + }); + + describe('getBid', function () { + let bidResponse; + let loadConfig; + let getPricingCalled; + + beforeEach(function () { + // Mock VastLoader for test purpose + window.com = { + stickyadstv: { + vast: { + VastLoader: function() { + this.getVast = function() { + return { + getPricing: function() { + getPricingCalled = true; + return {currency: 'USD', price: 4.000} + } + }; + }; + + this.load = function(config, listener) { + loadConfig = config; + listener.onSuccess(); + }; + } + }, + screenroll: { + getPlayerSize: function() { + return '123x456'; + } + } + } + }; + + adapter.getBid(bidderRequest.bids[0], function(bidObject) { + bidResponse = bidObject; + }); + }); + + afterEach(function() { + delete window.com.stickyadstv.vast.VastLoader; + delete window.com.stickyadstv.vast; + delete window.com.stickyadstv.screenroll; + delete window.com.stickyadstv; + }); + + it('should return a valid bidObject', function () { + expect(bidResponse).to.have.property('cpm', 4.000); + expect(bidResponse).to.have.property('ad', ""); + expect(bidResponse).to.have.property('bidderCode', 'stickyadstv'); + expect(bidResponse).to.have.property('currencyCode', 'USD'); + expect(bidResponse).to.have.property('width', 300); + expect(bidResponse).to.have.property('height', 250); + expect(bidResponse.getStatusCode()).to.equal(1); + }); + + it('should have called load with proper config', function () { + expect(loadConfig).to.have.property('playerSize', '123x456'); + expect(loadConfig).to.have.property('zoneId', '2003'); + }); + + it('should have called getPricing', function () { + expect(getPricingCalled).to.equal(true); + }); + }); + + describe('formatBidObject', function () { + it('should create a valid bid object', function () { + let result = adapter.formatBidObject('', true, {currency: 'EUR', price: '1.2345'}, '
sample
', 200, 300); + + expect(result).to.have.property('cpm', '1.2345'); + expect(result).to.have.property('ad', '
sample
'); + expect(result).to.have.property('currencyCode', 'EUR'); + expect(result).to.have.property('width', 200); + expect(result).to.have.property('height', 300); + expect(result.getStatusCode()).to.equal(1); + }); + + it('should create a invalid bid object because price is not defined', function () { + let result = adapter.formatBidObject('', true, null, '
sample
', 200, 300); + + expect(result.getStatusCode()).to.equal(2); + }); + + it('should create a invalid bid object', function () { + let result = adapter.formatBidObject('', false, {currency: 'EUR', price: '1.2345'}, '
sample
', 200, 300); + + expect(result.getStatusCode()).to.equal(2); + }); + }); + + describe('formatAdHTML', function () { + it('should create an inBanner ad format', function () { + let result = adapter.formatAdHTML({placementCode: 'placementCodeValue', params: {}}, [200, 300]); + + expect(result).to.equal('
'); + }); + + it('should create an intext ad format', function () { + let result = adapter.formatAdHTML({placementCode: 'placementCodeValue', params: {format: 'intext-roll', auto: 'v2', smartPlay: 'true'}}, [200, 300]); + + expect(result).to.equal(''); + }); + + it('should create a screenroll ad format', function () { + let result = adapter.formatAdHTML({placementCode: 'placementCodeValue', params: {format: 'screen-roll', smartPlay: 'true'}}, [200, 300]); + + expect(result).to.equal(''); + }); + }); + + describe('getBiggerSize', function () { + it('should return the bigger size', function () { + let result = adapter.getBiggerSize([[1, 4000], [4000, 1], [200, 300], [0, 0]]); + + expect(result[0]).to.equal(200); + expect(result[1]).to.equal(300); + }); + }); + + describe('top most window', function () { + it('should return the top most window', function () { + let result = adapter.getTopMostWindow(); + + expect(result).to.equal(window.top); + }); + }); + + describe('get component id', function() { + it('should return valid component ids', function() { + expect(adapter.getComponentId('inbanner')).to.equal('mustang'); + expect(adapter.getComponentId('intext-roll')).to.equal('intext-roll'); + expect(adapter.getComponentId('screen-roll')).to.equal('screen-roll'); + }); + }); + + describe('get API name', function() { + it('should return valid API names', function() { + expect(adapter.getAPIName()).to.equal(''); + expect(adapter.getAPIName('intext-roll')).to.equal('intextroll'); + expect(adapter.getAPIName('screen-roll')).to.equal('screenroll'); + expect(adapter.getAPIName('floorad')).to.equal('floorad'); + }); + }); +}); diff --git a/test/spec/adapters/tapsense_spec.js b/test/spec/modules/tapsenseBidAdapter_spec.js similarity index 61% rename from test/spec/adapters/tapsense_spec.js rename to test/spec/modules/tapsenseBidAdapter_spec.js index 72d189ef81e..997f0ca6c6e 100644 --- a/test/spec/adapters/tapsense_spec.js +++ b/test/spec/modules/tapsenseBidAdapter_spec.js @@ -1,78 +1,76 @@ import { expect } from 'chai'; -import Adapter from 'src/adapters/tapsense'; +import Adapter from 'modules/tapsenseBidAdapter'; import bidmanager from 'src/bidmanager'; -import adloader from "src/adloader"; -import * as utils from "src/utils"; - -window.pbjs = window.pbjs || {}; +import adloader from 'src/adloader'; +import * as utils from 'src/utils'; const DEFAULT_BIDDER_REQUEST = { - "bidderCode": "tapsense", - "bidderRequestId": "141ed07a281ca3", - "requestId": "b202e550-b0f7-4fb9-bfb4-1aa80f1795b4", - "start": new Date().getTime(), - "bids": [ + 'bidderCode': 'tapsense', + 'bidderRequestId': '141ed07a281ca3', + 'requestId': 'b202e550-b0f7-4fb9-bfb4-1aa80f1795b4', + 'start': new Date().getTime(), + 'bids': [ { - "sizes": undefined, //set values in tests - "bidder": "tapsense", - "bidId": "2b211418dd0575", - "bidderRequestId": "141ed07a281ca3", - "placementCode": "thisisatest", - "params": { - "ufid": "thisisaufid", - "refer": "thisisarefer", - "version": "0.0.1", - "ad_unit_id": "thisisanadunitid", - "device_id": "thisisadeviceid", - "lat": "thisislat", - "long": "thisisalong", - "user": "thisisanidfa", - "price_floor": 0.01 + 'sizes': undefined, // set values in tests + 'bidder': 'tapsense', + 'bidId': '2b211418dd0575', + 'bidderRequestId': '141ed07a281ca3', + 'placementCode': 'thisisatest', + 'params': { + 'ufid': 'thisisaufid', + 'refer': 'thisisarefer', + 'version': '0.0.1', + 'ad_unit_id': 'thisisanadunitid', + 'device_id': 'thisisadeviceid', + 'lat': 'thisislat', + 'long': 'thisisalong', + 'user': 'thisisanidfa', + 'price_floor': 0.01 } } ] -} +}; const SUCCESSFUL_RESPONSE = { - "count_ad_units": 1, - "status": { - "value": "ok", + 'count_ad_units': 1, + 'status': { + 'value': 'ok', }, - "ad_units": [ + 'ad_units': [ { - html: "", - imp_url: "https://i.tapsense.com" + html: '', + imp_url: 'https://i.tapsense.com' } ], - "id": "thisisanid", - "width": 320, - "height": 50, - "time": new Date().getTime() + 'id': 'thisisanid', + 'width': 320, + 'height': 50, + 'time': new Date().getTime() } const UNSUCCESSFUL_RESPONSE = { - "count_ad_units": 0, - "status": { - "value": "nofill" //will be set in test + 'count_ad_units': 0, + 'status': { + 'value': 'nofill' // will be set in test }, - "time": new Date().getTime() + 'time': new Date().getTime() } function duplicate(obj) { return JSON.parse(JSON.stringify(obj)); } -function makeSuccessfulRequest(adapter){ +function makeSuccessfulRequest(adapter) { let modifiedReq = duplicate(DEFAULT_BIDDER_REQUEST); - modifiedReq.bids[0].sizes = [[320,50], [500,500]]; + modifiedReq.bids[0].sizes = [[320, 50], [500, 500]]; adapter.callBids(modifiedReq); return modifiedReq.bids; } -describe ("TapSenseAdapter", () => { +describe('TapSenseAdapter', () => { let adapter, sandbox; beforeEach(() => { - adapter = new Adapter; + adapter = new Adapter(); sandbox = sinon.sandbox.create(); }); afterEach(() => { @@ -107,7 +105,7 @@ describe ("TapSenseAdapter", () => { }); it('does not make a request if ad sizes are incorrect', () => { let modifiedReq = duplicate(DEFAULT_BIDDER_REQUEST); - modifiedReq.bids[0].sizes = [[500,500]]; + modifiedReq.bids[0].sizes = [[500, 500]]; adapter.callBids(modifiedReq); sinon.assert.notCalled(adloader.loadScript); }); @@ -118,42 +116,42 @@ describe ("TapSenseAdapter", () => { sinon.assert.notCalled(adloader.loadScript); }); - describe("requesting an ad", () => { + describe('requesting an ad', () => { afterEach(() => { sandbox.restore(); }) - it("makes a request if valid sizes are provided (nested array)", () => { + it('makes a request if valid sizes are provided (nested array)', () => { makeSuccessfulRequest(adapter); sinon.assert.calledOnce(adloader.loadScript); expect(adloader.loadScript.firstCall.args[0]).to.contain( - "ads04.tapsense.com" + 'ads04.tapsense.com' ); }); - it("handles a singles array for size parameter", () => { + it('handles a singles array for size parameter', () => { let modifiedReq = duplicate(DEFAULT_BIDDER_REQUEST); - modifiedReq.bids[0].sizes = [320,50]; + modifiedReq.bids[0].sizes = [320, 50]; adapter.callBids(modifiedReq); expect(adloader.loadScript.firstCall.args[0]).to.contain( - "ads04.tapsense.com" + 'ads04.tapsense.com' ); }); - it("handles a string for size parameter", () => { + it('handles a string for size parameter', () => { let modifiedReq = duplicate(DEFAULT_BIDDER_REQUEST); - modifiedReq.bids[0].sizes = "320x50"; + modifiedReq.bids[0].sizes = '320x50'; adapter.callBids(modifiedReq); expect(adloader.loadScript.firstCall.args[0]).to.contain( - "ads04.tapsense.com" + 'ads04.tapsense.com' ); }); - it("handles a string with multiple sizes for size parameter", () => { + it('handles a string with multiple sizes for size parameter', () => { let modifiedReq = duplicate(DEFAULT_BIDDER_REQUEST); - modifiedReq.bids[0].sizes = "320x50,500x500"; + modifiedReq.bids[0].sizes = '320x50,500x500'; adapter.callBids(modifiedReq); expect(adloader.loadScript.firstCall.args[0]).to.contain( - "ads04.tapsense.com" + 'ads04.tapsense.com' ); }); - it("appends bid params as a query string when requesting ad", () => { + it('appends bid params as a query string when requesting ad', () => { makeSuccessfulRequest(adapter); sinon.assert.calledOnce(adloader.loadScript); expect(adloader.loadScript.firstCall.args[0]).to.match( @@ -193,68 +191,67 @@ describe ("TapSenseAdapter", () => { }) }); - describe("generateCallback", () => { + describe('generateCallback', () => { beforeEach(() => { sandbox.stub(adloader, 'loadScript'); }); afterEach(() => { sandbox.restore(); }); - it("generates callback in namespaced object with correct bidder id", () => { + it('generates callback in namespaced object with correct bidder id', () => { makeSuccessfulRequest(adapter); - expect(pbjs.tapsense.callback_with_price_2b211418dd0575).to.exist.and.to.be.a('function'); + expect($$PREBID_GLOBAL$$.tapsense.callback_with_price_2b211418dd0575).to.exist.and.to.be.a('function'); }) }); - describe("response", () => { + describe('response', () => { beforeEach(() => { sandbox.stub(bidmanager, 'addBidResponse'); sandbox.stub(adloader, 'loadScript'); let bids = makeSuccessfulRequest(adapter); - sandbox.stub(utils, "getBidRequest", (id) => { - return bids.find((item) => { return item.bidId === id}); + sandbox.stub(utils, 'getBidRequest', (id) => { + return bids.find((item) => { return item.bidId === id }); }) }); afterEach(() => { sandbox.restore(); }); - describe("successful response", () => { + describe('successful response', () => { beforeEach(() => { - pbjs.tapsense.callback_with_price_2b211418dd0575(SUCCESSFUL_RESPONSE, 1.2); + $$PREBID_GLOBAL$$.tapsense.callback_with_price_2b211418dd0575(SUCCESSFUL_RESPONSE, 1.2); }); - it("called the bidmanager and registers a bid", () => { + it('called the bidmanager and registers a bid', () => { sinon.assert.calledOnce(bidmanager.addBidResponse); expect(bidmanager.addBidResponse.firstCall.args[1].getStatusCode()).to.equal(1); }); - it("should have the correct placementCode", () => { + it('should have the correct placementCode', () => { sinon.assert.calledOnce(bidmanager.addBidResponse); - expect(bidmanager.addBidResponse.firstCall.args[0]).to.equal("thisisatest"); + expect(bidmanager.addBidResponse.firstCall.args[0]).to.equal('thisisatest'); }); }); - describe("unsuccessful response", () => { + describe('unsuccessful response', () => { beforeEach(() => { - pbjs.tapsense.callback_with_price_2b211418dd0575(UNSUCCESSFUL_RESPONSE, 1.2); + $$PREBID_GLOBAL$$.tapsense.callback_with_price_2b211418dd0575(UNSUCCESSFUL_RESPONSE, 1.2); }) - it("should call the bidmanger and register an invalid bid", () => { + it('should call the bidmanger and register an invalid bid', () => { sinon.assert.calledOnce(bidmanager.addBidResponse); expect(bidmanager.addBidResponse.firstCall.args[1].getStatusCode()).to.equal(2); }); - it("should have the correct placementCode", () => { - expect(bidmanager.addBidResponse.firstCall.args[0]).to.equal("thisisatest"); + it('should have the correct placementCode', () => { + expect(bidmanager.addBidResponse.firstCall.args[0]).to.equal('thisisatest'); }) }); - describe("no response/timeout", () => { - it("should not register any bids", () => { + describe('no response/timeout', () => { + it('should not register any bids', () => { sinon.assert.notCalled(bidmanager.addBidResponse); }) }); - describe("edge cases", () => { - it("does not register a bid if no price is supplied", () => { - sandbox.stub(utils, "logMessage"); - pbjs.tapsense.callback_with_price_2b211418dd0575(SUCCESSFUL_RESPONSE); + describe('edge cases', () => { + it('does not register a bid if no price is supplied', () => { + sandbox.stub(utils, 'logMessage'); + $$PREBID_GLOBAL$$.tapsense.callback_with_price_2b211418dd0575(SUCCESSFUL_RESPONSE); sinon.assert.notCalled(bidmanager.addBidResponse); }); }); }); - }) diff --git a/test/spec/adapters/thoughtleadr_spec.js b/test/spec/modules/thoughtleadrBidAdapter_spec.js similarity index 65% rename from test/spec/adapters/thoughtleadr_spec.js rename to test/spec/modules/thoughtleadrBidAdapter_spec.js index 67be54f3aef..43c13ebc21f 100644 --- a/test/spec/adapters/thoughtleadr_spec.js +++ b/test/spec/modules/thoughtleadrBidAdapter_spec.js @@ -1,8 +1,8 @@ -"use strict"; -var chai_1 = require("chai"); -var ta = require("../../../src/adapters/thoughtleadr"); -var adloader = require("../../../src/adloader"); -var bidfactory = require("../../../src/bidfactory"); +'use strict'; +var chai_1 = require('chai'); +var ta = require('../../../modules/thoughtleadrBidAdapter'); +var adloader = require('../../../src/adloader'); +var bidfactory = require('../../../src/bidfactory'); var Adapter = ta; function setupResponse(resp) { @@ -17,7 +17,7 @@ function setupResponse(resp) { return stub; } -describe("thoughtleadr adapter tests", function () { +describe('thoughtleadr adapter tests', function () { var sandbox; var adapter; var request; @@ -30,18 +30,18 @@ describe("thoughtleadr adapter tests", function () { }); beforeEach(function () { - loadScript = sandbox.stub(adloader, "loadScript"); - createBid = sandbox.spy(bidfactory, "createBid"); + loadScript = sandbox.stub(adloader, 'loadScript'); + createBid = sandbox.spy(bidfactory, 'createBid'); adapter = new Adapter(); loadScript.reset(); request = { - bidderCode: "thoughtleadr", + bidderCode: 'thoughtleadr', bids: [{ - bidder: "thoughtleadr", - placementCode: "abc-123", + bidder: 'thoughtleadr', + placementCode: 'abc-123', sizes: [[300, 250], [400, 400]], params: { - placementId: "test-placement" + placementId: 'test-placement' } }] }; @@ -53,8 +53,7 @@ describe("thoughtleadr adapter tests", function () { sandbox.restore(); }); - describe("callBids", function () { - + describe('callBids', function () { beforeEach(function () { tldrRequestPrebid = setupResponse({}); }); @@ -62,55 +61,53 @@ describe("thoughtleadr adapter tests", function () { it("should request page.js from cdn if there wasn't before", function () { delete window.tldr; adapter.callBids(request); - chai_1.expect(loadScript.getCall(0).args[0]).to.be.equal("//cdn.thoughtleadr.com/v4/page.js"); + chai_1.expect(loadScript.getCall(0).args[0]).to.be.equal('//cdn.thoughtleadr.com/v4/page.js'); }); - it("should use window.tldr.config.root_url", function () { + it('should use window.tldr.config.root_url', function () { window.tldr = { config: { - root_url: "http://example.loc/" + root_url: 'http://example.loc/' } }; adapter.callBids(request); - chai_1.expect(loadScript.getCall(0).args[0]).to.be.equal("http://example.loc/page.js"); + chai_1.expect(loadScript.getCall(0).args[0]).to.be.equal('http://example.loc/page.js'); }); - it("should not request page.js if api is present", function () { + it('should not request page.js if api is present', function () { adapter.callBids(request); chai_1.expect(loadScript.notCalled).to.be.ok; }); }); - describe("handleBids", function () { - + describe('handleBids', function () { beforeEach(function () { tldrRequestPrebid = setupResponse({}); }); - it("should filter invalid bids", function () { + it('should filter invalid bids', function () { request.bids.unshift({ - bidder: "thoughtleadr", - placementCode: "abc-123", + bidder: 'thoughtleadr', + placementCode: 'abc-123', sizes: [[300, 250], [400, 400]], params: {} }); request.bids.push({ - bidder: "thoughtleadr", - placementCode: "abc-123", + bidder: 'thoughtleadr', + placementCode: 'abc-123', sizes: [[300, 250], [400, 400]], params: { incorrectParam: 123 } }); - var requestPlacement = sinon.spy(adapter, "requestPlacement"); + var requestPlacement = sinon.spy(adapter, 'requestPlacement'); adapter.callBids(request); chai_1.expect(requestPlacement.callCount).to.be.equal(1); chai_1.expect(requestPlacement.getCall(0).args[0]).to.be.equal(request.bids[1]); }); }); - describe("requestPlacement", function () { - + describe('requestPlacement', function () { beforeEach(function () { tldrRequestPrebid = setupResponse({ config: { @@ -119,19 +116,19 @@ describe("thoughtleadr adapter tests", function () { bid: { code: 1, cpm: 12, - ad: "asd" + ad: 'asd' } }); }); - it("should made request through page.js api", function () { + it('should made request through page.js api', function () { adapter.callBids(request); chai_1.expect(tldrRequestPrebid.callCount).to.be.equal(1); chai_1.expect(tldrRequestPrebid.firstCall.args[0]).to.be.equal(request.bids[0].params.placementId); chai_1.expect(tldrRequestPrebid.firstCall.args[1]).to.be.length(36); }); - it("should call bidfactory.createBid with code 1 if ad is ok", function () { + it('should call bidfactory.createBid with code 1 if ad is ok', function () { var bid = request.bids[0]; adapter.requestPlacement(bid); chai_1.expect(createBid.callCount).to.be.equal(1); @@ -151,26 +148,24 @@ describe("thoughtleadr adapter tests", function () { chai_1.expect(createBid.firstCall.args[0]).to.be.equal(2); }); - it.skip("should response on the postMessage request", function (done) { + it.skip('should response on the postMessage request', function (done) { var bid = request.bids[0]; adapter.requestPlacement(bid); var rid = tldrRequestPrebid.firstCall.args[1]; chai_1.expect(rid).to.be.ok; - window.addEventListener("message", function (ev) { + window.addEventListener('message', function (ev) { if (ev.data && ev.data.TLDR_RESPONSE) { chai_1.expect(ev.data.TLDR_RESPONSE.rid).to.be.equal(rid); chai_1.expect(JSON.stringify(ev.data.TLDR_RESPONSE.config)).to.be.equal('{"abc":567}'); done(); - } - else if (ev.data && ev.data.TLDR_REQUEST) { + } else if (ev.data && ev.data.TLDR_REQUEST) { chai_1.expect(ev.data.TLDR_REQUEST.rid).to.be.equal(rid); - } - else { - throw new Error("should not be any other messages"); + } else { + throw new Error('should not be any other messages'); } }, false); - window.postMessage({TLDR_REQUEST: {rid: rid}}, "*"); + window.postMessage({TLDR_REQUEST: {rid: rid}}, '*'); }); }); }); diff --git a/test/spec/adapters/trion_spec.js b/test/spec/modules/trionBidAdapter_spec.js similarity index 79% rename from test/spec/adapters/trion_spec.js rename to test/spec/modules/trionBidAdapter_spec.js index 416d4313c87..50988c564ec 100644 --- a/test/spec/adapters/trion_spec.js +++ b/test/spec/modules/trionBidAdapter_spec.js @@ -1,45 +1,45 @@ import { expect } from 'chai'; -import trionAdapter from 'src/adapters/trion'; +import trionAdapter from 'modules/trionBidAdapter'; import bidmanager from 'src/bidmanager'; +import * as utils from 'src/utils'; const CONSTANTS = require('src/constants.json'); const adloader = require('src/adloader'); const PLACEMENT_CODE = 'ad-tag'; -const BID_REQUEST_BASE_URL = "https://in-appadvertising.com/api/bidRequest?"; -const USER_SYNC_URL = "https://in-appadvertising.com/api/userSync.js"; +const BID_REQUEST_BASE_URL = 'https://in-appadvertising.com/api/bidRequest?'; +const USER_SYNC_URL = 'https://in-appadvertising.com/api/userSync.js'; const TRION_BID_REQUEST = { - bidderCode: "trion", + bidderCode: 'trion', bids: [ { - bidder: "trion", + bidder: 'trion', params: { - pubId : '1', - sectionId : '2' + pubId: '1', + sectionId: '2' }, placementCode: PLACEMENT_CODE, sizes: [[300, 250], [300, 600]], - bidId: "test-bid-id" + bidId: 'test-bid-id' } ] }; const TRION_BID_RESPONSE = { - bidId : 'test-bid-id', + bidId: 'test-bid-id', sizes: [[300, 250], [300, 600]], - result : { - cpm : 100, + result: { + cpm: 100, placeBid: true, - height: "250", - width: "300", - ad : 'test', - msg : 'response messaging' + height: '250', + width: '300', + ad: 'test', + msg: 'response messaging' } }; describe('Trion adapter tests', () => { - let adapter; beforeEach(() => { @@ -59,7 +59,7 @@ describe('Trion adapter tests', () => { beforeEach(() => { spyLoadScript = sinon.spy(adloader, 'loadScript'); window.TRION_INT = { - int_t : -1 + int_t: -1 }; }); @@ -85,7 +85,7 @@ describe('Trion adapter tests', () => { let bidUrl = spyLoadScript.getCall(0).args[0]; expect(bidUrl).to.include(BID_REQUEST_BASE_URL); }); - + it('should call loadscript with the correct required params', function () { adapter.callBids(TRION_BID_REQUEST); @@ -107,29 +107,29 @@ describe('Trion adapter tests', () => { let bidUrl = spyLoadScript.getCall(0).args[0]; expect(bidUrl).to.include('re=1'); - expect(bidUrl).to.include(window.location.href); + expect(bidUrl).to.include(utils.getTopWindowUrl()); + expect(bidUrl).to.include('slot=' + PLACEMENT_CODE); delete params.re; }); - - describe('user sync', ()=> { - + + describe('user sync', () => { beforeEach(() => { delete window.TRION_INT; delete window.TR_INT_T; }); - - it('user sync is called', ()=> { + + it('user sync is called', () => { adapter.callBids(TRION_BID_REQUEST); sinon.assert.calledWith(spyLoadScript, USER_SYNC_URL); }); - it('user sync tag is included in bid url', ()=> { + it('user sync tag is included in bid url', () => { window.TRION_INT = { - campaigns : [ + campaigns: [ 'campaign1', 'campaign2' ], - int_t : 'int_t' + int_t: 'int_t' }; let userTag = encodeURIComponent(JSON.stringify(window.TRION_INT)); adapter.callBids(TRION_BID_REQUEST); @@ -138,20 +138,20 @@ describe('Trion adapter tests', () => { expect(bidUrl).to.include(userTag); }); - it('user sync tag is included in bid url and includes the correct int_t', ()=> { + it('user sync tag is included in bid url and includes the correct int_t', () => { window.TRION_INT = { - campaigns : [ + campaigns: [ 'campaign1', 'campaign2' ] }; let int_t = 'test'; let expectedObject = { - campaigns : [ + campaigns: [ 'campaign1', 'campaign2' ], - int_t : int_t + int_t: int_t }; window.TR_INT_T = int_t; let userTag = encodeURIComponent(JSON.stringify(expectedObject)); @@ -160,21 +160,21 @@ describe('Trion adapter tests', () => { let bidUrl = spyLoadScript.getCall(0).args[0]; expect(bidUrl).to.include(userTag); }); - - it('user sync tag variable int_t cannot be changed once set', ()=> { + + it('user sync tag variable int_t cannot be changed once set', () => { window.TRION_INT = { - campaigns : [ + campaigns: [ 'campaign1', 'campaign2' ] }; let int_t = 'test'; let expectedObject = { - campaigns : [ + campaigns: [ 'campaign1', 'campaign2' ], - int_t : int_t + int_t: int_t }; window.TR_INT_T = int_t; let userTag = encodeURIComponent(JSON.stringify(expectedObject)); @@ -185,13 +185,10 @@ describe('Trion adapter tests', () => { expect(bidUrl).to.include(userTag); expect(bidUrl).to.not.include('bad'); }); - }); - }); describe('response handler', () => { - beforeEach(() => { sinon.stub(bidmanager, 'addBidResponse'); }); @@ -201,8 +198,8 @@ describe('Trion adapter tests', () => { }); it('when there is no response do not bid', function () { - pbjs._bidsRequested.push(TRION_BID_REQUEST); - pbjs.handleTrionCB(); + $$PREBID_GLOBAL$$._bidsRequested.push(TRION_BID_REQUEST); + $$PREBID_GLOBAL$$.handleTrionCB(); sinon.assert.calledOnce(bidmanager.addBidResponse); const response = bidmanager.addBidResponse.firstCall.args[1]; expect(response.getStatusCode()).to.equal(CONSTANTS.STATUS.NO_BID); @@ -210,8 +207,8 @@ describe('Trion adapter tests', () => { it('when place bid is returned as false', function () { TRION_BID_RESPONSE.result.placeBid = false; - pbjs._bidsRequested.push(TRION_BID_REQUEST); - pbjs.handleTrionCB(TRION_BID_RESPONSE); + $$PREBID_GLOBAL$$._bidsRequested.push(TRION_BID_REQUEST); + $$PREBID_GLOBAL$$.handleTrionCB(TRION_BID_RESPONSE); sinon.assert.calledOnce(bidmanager.addBidResponse); const response = bidmanager.addBidResponse.firstCall.args[1]; expect(response.getStatusCode()).to.equal(CONSTANTS.STATUS.NO_BID); @@ -220,8 +217,8 @@ describe('Trion adapter tests', () => { it('when no cpm is in the response', function () { TRION_BID_RESPONSE.result.cpm = 0; - pbjs._bidsRequested.push(TRION_BID_REQUEST); - pbjs.handleTrionCB(TRION_BID_RESPONSE); + $$PREBID_GLOBAL$$._bidsRequested.push(TRION_BID_REQUEST); + $$PREBID_GLOBAL$$.handleTrionCB(TRION_BID_RESPONSE); sinon.assert.calledOnce(bidmanager.addBidResponse); const response = bidmanager.addBidResponse.firstCall.args[1]; expect(response.getStatusCode()).to.equal(CONSTANTS.STATUS.NO_BID); @@ -230,8 +227,8 @@ describe('Trion adapter tests', () => { it('when no ad is in the response', function () { TRION_BID_RESPONSE.result.ad = null; - pbjs._bidsRequested.push(TRION_BID_REQUEST); - pbjs.handleTrionCB(TRION_BID_RESPONSE); + $$PREBID_GLOBAL$$._bidsRequested.push(TRION_BID_REQUEST); + $$PREBID_GLOBAL$$.handleTrionCB(TRION_BID_RESPONSE); sinon.assert.calledOnce(bidmanager.addBidResponse); const response = bidmanager.addBidResponse.firstCall.args[1]; expect(response.getStatusCode()).to.equal(CONSTANTS.STATUS.NO_BID); @@ -239,8 +236,8 @@ describe('Trion adapter tests', () => { }); it('bid response is formatted correctly', function () { - pbjs._bidsRequested.push(TRION_BID_REQUEST); - pbjs.handleTrionCB(TRION_BID_RESPONSE); + $$PREBID_GLOBAL$$._bidsRequested.push(TRION_BID_REQUEST); + $$PREBID_GLOBAL$$.handleTrionCB(TRION_BID_RESPONSE); const placementCode = bidmanager.addBidResponse.firstCall.args[0]; const response = bidmanager.addBidResponse.firstCall.args[1]; expect(placementCode).to.equal(PLACEMENT_CODE); @@ -253,8 +250,8 @@ describe('Trion adapter tests', () => { let bidHeight = '2'; TRION_BID_RESPONSE.result.width = bidWidth; TRION_BID_RESPONSE.result.height = bidHeight; - pbjs._bidsRequested.push(TRION_BID_REQUEST); - pbjs.handleTrionCB(TRION_BID_RESPONSE); + $$PREBID_GLOBAL$$._bidsRequested.push(TRION_BID_REQUEST); + $$PREBID_GLOBAL$$.handleTrionCB(TRION_BID_RESPONSE); const placementCode = bidmanager.addBidResponse.firstCall.args[0]; const response = bidmanager.addBidResponse.firstCall.args[1]; expect(response.width).to.equal(bidWidth); @@ -266,12 +263,11 @@ describe('Trion adapter tests', () => { it('cpm is properly set and transformed to cents', function () { let bidCpm = 2; TRION_BID_RESPONSE.result.cpm = bidCpm * 100; - pbjs._bidsRequested.push(TRION_BID_REQUEST); - pbjs.handleTrionCB(TRION_BID_RESPONSE); + $$PREBID_GLOBAL$$._bidsRequested.push(TRION_BID_REQUEST); + $$PREBID_GLOBAL$$.handleTrionCB(TRION_BID_RESPONSE); const response = bidmanager.addBidResponse.firstCall.args[1]; expect(response.cpm).to.equal(bidCpm); TRION_BID_RESPONSE.result.cpm = 100; }); - }); }); diff --git a/test/spec/adapters/triplelift_spec.js b/test/spec/modules/tripleliftBidAdapter_spec.js similarity index 76% rename from test/spec/adapters/triplelift_spec.js rename to test/spec/modules/tripleliftBidAdapter_spec.js index 6e2b748c7d6..95658883fd0 100644 --- a/test/spec/adapters/triplelift_spec.js +++ b/test/spec/modules/tripleliftBidAdapter_spec.js @@ -1,11 +1,10 @@ import {expect} from 'chai'; -import Adapter from '../../../src/adapters/triplelift'; +import Adapter from '../../../modules/tripleliftBidAdapter'; import bidManager from '../../../src/bidmanager'; import adLoader from '../../../src/adloader'; import {parse as parseURL} from '../../../src/url'; describe('triplelift adapter', () => { - let bidsRequestedOriginal; let adapter; let sandbox; @@ -36,8 +35,8 @@ describe('triplelift adapter', () => { }; beforeEach(() => { - bidsRequestedOriginal = pbjs._bidsRequested; - pbjs._bidsRequested = []; + bidsRequestedOriginal = $$PREBID_GLOBAL$$._bidsRequested; + $$PREBID_GLOBAL$$._bidsRequested = []; adapter = new Adapter(); sandbox = sinon.sandbox.create(); @@ -46,11 +45,10 @@ describe('triplelift adapter', () => { afterEach(() => { sandbox.restore(); - pbjs._bidsRequested = bidsRequestedOriginal; + $$PREBID_GLOBAL$$._bidsRequested = bidsRequestedOriginal; }); describe('callBids', () => { - let firstBidScriptURL; let secondBidScriptURL; @@ -70,63 +68,59 @@ describe('triplelift adapter', () => { expect(secondBidScriptURL).to.contain(route); let firstScriptParams = parseURL(firstBidScriptURL).search; - expect(firstScriptParams).to.have.property('callback','pbjs.TLCB'); - expect(firstScriptParams).to.have.property('callback_id','bidId1'); - expect(firstScriptParams).to.have.property('inv_code','codeA'); - expect(firstScriptParams).to.have.property('size','728x90'); + expect(firstScriptParams).to.have.property('callback', '$$PREBID_GLOBAL$$.TLCB'); + expect(firstScriptParams).to.have.property('callback_id', 'bidId1'); + expect(firstScriptParams).to.have.property('inv_code', 'codeA'); + expect(firstScriptParams).to.have.property('size', '728x90'); expect(firstScriptParams).to.have.property('referrer'); let secondScriptParams = parseURL(secondBidScriptURL).search; - expect(secondScriptParams).to.have.property('callback','pbjs.TLCB'); - expect(secondScriptParams).to.have.property('callback_id','bidId2'); - expect(secondScriptParams).to.have.property('inv_code','codeB'); - expect(secondScriptParams).to.have.property('size','300x600'); - expect(secondScriptParams).to.have.property('floor','1'); + expect(secondScriptParams).to.have.property('callback', '$$PREBID_GLOBAL$$.TLCB'); + expect(secondScriptParams).to.have.property('callback_id', 'bidId2'); + expect(secondScriptParams).to.have.property('inv_code', 'codeB'); + expect(secondScriptParams).to.have.property('size', '300x600'); + expect(secondScriptParams).to.have.property('floor', '1'); expect(secondScriptParams).to.have.property('referrer'); }); - }); describe('TLCB', () => { - it('should exist and be a function', () => { - expect(pbjs.TLCB).to.exist.and.to.be.a('function'); + expect($$PREBID_GLOBAL$$.TLCB).to.exist.and.to.be.a('function'); }); - }); describe('add bids to the manager', () => { - let firstBid; let secondBid; beforeEach(() => { sandbox.stub(bidManager, 'addBidResponse'); - pbjs._bidsRequested.push(bidderRequest); + $$PREBID_GLOBAL$$._bidsRequested.push(bidderRequest); // respond let bidderReponse1 = { - "ad": "", - "callback_id": "bidId1", - "cpm": 0.20, - "height": 90, - "iurl": "", - "width": 728 + 'ad': '', + 'callback_id': 'bidId1', + 'cpm': 0.20, + 'height': 90, + 'iurl': '', + 'width': 728 }; let bidderReponse2 = { - "ad": "", - "callback_id": "bidId2", - "cpm": 0.30, - "height": 600, - "iurl": "", - "width": 300, - "deal_id": "dealA" + 'ad': '', + 'callback_id': 'bidId2', + 'cpm': 0.30, + 'height': 600, + 'iurl': '', + 'width': 300, + 'deal_id': 'dealA' }; - pbjs.TLCB(bidderReponse1); - pbjs.TLCB(bidderReponse2); + $$PREBID_GLOBAL$$.TLCB(bidderReponse1); + $$PREBID_GLOBAL$$.TLCB(bidderReponse2); firstBid = bidManager.addBidResponse.firstCall.args[1]; secondBid = bidManager.addBidResponse.secondCall.args[1]; @@ -183,21 +177,20 @@ describe('triplelift adapter', () => { }); describe('add empty bids if no bid returned', () => { - let firstBid; let secondBid; beforeEach(() => { sandbox.stub(bidManager, 'addBidResponse'); - pbjs._bidsRequested.push(bidderRequest); + $$PREBID_GLOBAL$$._bidsRequested.push(bidderRequest); // respond - let bidderReponse1 = {"status":"no_bid","callback_id":"bidId1"}; - let bidderReponse2 = {"status":"no_bid","callback_id":"bidId2"}; + let bidderReponse1 = {'status': 'no_bid', 'callback_id': 'bidId1'}; + let bidderReponse2 = {'status': 'no_bid', 'callback_id': 'bidId2'}; - pbjs.TLCB(bidderReponse1); - pbjs.TLCB(bidderReponse2); + $$PREBID_GLOBAL$$.TLCB(bidderReponse1); + $$PREBID_GLOBAL$$.TLCB(bidderReponse2); firstBid = bidManager.addBidResponse.firstCall.args[1]; secondBid = bidManager.addBidResponse.secondCall.args[1]; @@ -229,6 +222,5 @@ describe('triplelift adapter', () => { expect(firstBid).to.have.property('bidderCode', 'triplelift'); expect(secondBid).to.have.property('bidderCode', 'triplelift'); }); - }); }); diff --git a/test/spec/modules/twengaBidAdapter_spec.js b/test/spec/modules/twengaBidAdapter_spec.js new file mode 100644 index 00000000000..feaa44ca438 --- /dev/null +++ b/test/spec/modules/twengaBidAdapter_spec.js @@ -0,0 +1,119 @@ +describe('twenga adapter tests', function () { + var urlParse = require('url-parse'); + var querystringify = require('querystringify'); + var adapter = require('modules/twengaBidAdapter'); + var adLoader = require('src/adloader'); + var expect = require('chai').expect; + var bidmanager = require('src/bidmanager'); + var CONSTANTS = require('src/constants.json'); + + var DEFAULT_PARAMS = { + bidderCode: 'twenga', + bids: [{ + bidId: 'tw_abcd1234', + sizes: [[300, 250], [300, 200]], + bidder: 'twenga', + params: { + placementId: 'test', + siteId: 1234, + publisherId: 5678, + currency: 'USD', + bidFloor: 0.5, + country: 'DE' + }, + requestId: 'tw_efgh5678', + placementCode: 'tw_42' + }] + }; + + var BID_RESPONSE = { + result: { + cpm: 10000, + width: 300, + height: 250, + ad: '//rtb.t.c4tw.net', + creative_id: 'test' + }, + callback_uid: 'tw_abcd1234' + }; + + it('sets url parameters', function () { + var stubLoadScript = sinon.stub(adLoader, 'loadScript'); + + adapter().callBids(DEFAULT_PARAMS); + + var bidUrl = stubLoadScript.getCall(0).args[0]; + var parsedBidUrl = urlParse(bidUrl); + var parsedBidUrlQueryString = querystringify.parse(parsedBidUrl.query); + + expect(parsedBidUrl.hostname).to.equal('rtb.t.c4tw.net'); + expect(parsedBidUrl.pathname).to.equal('/Bid'); + + expect(parsedBidUrlQueryString).to.have.property('s').and.to.equal('h'); + expect(parsedBidUrlQueryString).to.have.property('callback').and.to.equal('$$PREBID_GLOBAL$$.handleTwCB'); + expect(parsedBidUrlQueryString).to.have.property('callback_uid').and.to.equal('tw_abcd1234'); + expect(parsedBidUrlQueryString).to.have.property('id').and.to.equal('test'); + + stubLoadScript.restore(); + }); + + var stringToFunction = function (s) { + var scope = global; + var scopeSplit = s.split('.'); + for (var i = 0; i < scopeSplit.length - 1; i++) { + scope = scope[scopeSplit[i]]; + if (scope == undefined) return; + } + return scope[scopeSplit[scopeSplit.length - 1]]; + }; + + it('creates an empty bid response if no bids', function() { + var stubLoadScript = sinon.stub(adLoader, 'loadScript', function(url) { + var bidUrl = stubLoadScript.getCall(0).args[0]; + var parsedBidUrl = urlParse(bidUrl); + var parsedBidUrlQueryString = querystringify.parse(parsedBidUrl.query); + + var callback = stringToFunction(parsedBidUrlQueryString.callback); + expect(callback).to.exist.and.to.be.a('function'); + callback(undefined); + }); + var stubAddBidResponse = sinon.stub(bidmanager, 'addBidResponse'); + + adapter.createNew().callBids(DEFAULT_PARAMS); + + expect(stubAddBidResponse.getCall(0)).to.be.null; + + stubAddBidResponse.restore(); + stubLoadScript.restore(); + }); + + it('creates a bid response if bid is returned', function() { + var stubLoadScript = sinon.stub(adLoader, 'loadScript', function(url) { + var bidUrl = stubLoadScript.getCall(0).args[0]; + var parsedBidUrl = urlParse(bidUrl); + var parsedBidUrlQueryString = querystringify.parse(parsedBidUrl.query); + + $$PREBID_GLOBAL$$._bidsRequested + .push({ bidderCode: DEFAULT_PARAMS.bidderCode, + bids: [{ bidId: parsedBidUrlQueryString.callback_uid, + placementCode: DEFAULT_PARAMS.bids[0].placementCode }]}); + + var callback = stringToFunction(parsedBidUrlQueryString.callback); + expect(callback).to.exist.and.to.be.a('function'); + callback(BID_RESPONSE); + }); + var stubAddBidResponse = sinon.stub(bidmanager, 'addBidResponse'); + + adapter.createNew().callBids(DEFAULT_PARAMS); + + var bidResponseAd = stubAddBidResponse.getCall(0).args[1]; + + expect(bidResponseAd).to.have.property('cpm').and.to.equal(BID_RESPONSE.result.cpm / 10000); + expect(bidResponseAd).to.have.property('adUrl').and.to.equal(BID_RESPONSE.result.ad); + expect(bidResponseAd).to.have.property('width').and.to.equal(BID_RESPONSE.result.width); + expect(bidResponseAd).to.have.property('height').and.to.equal(BID_RESPONSE.result.height); + + stubAddBidResponse.restore(); + stubLoadScript.restore(); + }); +}); diff --git a/test/spec/modules/ucfunnelBidAdapter_spec.js b/test/spec/modules/ucfunnelBidAdapter_spec.js new file mode 100644 index 00000000000..d8ddfc041b6 --- /dev/null +++ b/test/spec/modules/ucfunnelBidAdapter_spec.js @@ -0,0 +1,110 @@ +import { expect } from 'chai'; +import Adapter from 'modules/ucfunnelBidAdapter'; +import adapterManager from 'src/adaptermanager'; +import bidManager from 'src/bidmanager'; +import CONSTANTS from 'src/constants.json'; + +describe('ucfunnel adapter tests', function () { + let sandbox; + const adUnit = { // TODO CHANGE + code: 'ucfunnel', + sizes: [[300, 250]], + bids: [{ + bidder: 'ucfunnel', + params: { + adid: 'test-ad-83444226E44368D1E32E49EEBE6D29', + width: 300, + height: 250 + } + }] + }; + + const response = { + ad_id: 'ad-83444226E44368D1E32E49EEBE6D29', + adm: '
', + cpm: 0.01, + height: 250, + width: 300 + }; + + beforeEach(() => { + sandbox = sinon.sandbox.create(); + }); + + afterEach(() => { + sandbox.restore(); + }); + + describe('ucfunnel callBids validation', () => { + let bids, + server; + + beforeEach(() => { + bids = []; + server = sinon.fakeServer.create(); + + sandbox.stub(bidManager, 'addBidResponse', (elemId, bid) => { + bids.push(bid); + }); + }); + + afterEach(() => { + server.restore(); + }); + + let adapter = adapterManager.bidderRegistry['ucfunnel']; + + it('Valid bid-request', () => { + sandbox.stub(adapter, 'callBids'); + adapterManager.callBids({ + adUnits: [clone(adUnit)] + }); + + let bidderRequest = adapter.callBids.getCall(0).args[0]; + + expect(bidderRequest).to.have.property('bids') + .that.is.an('array') + .with.lengthOf(1); + + expect(bidderRequest).to.have.deep.property('bids[0]') + .to.have.property('bidder', 'ucfunnel'); + + expect(bidderRequest).to.have.deep.property('bids[0]') + .with.property('sizes') + .that.is.an('array') + .with.lengthOf(1) + .that.deep.equals(adUnit.sizes); + expect(bidderRequest).to.have.deep.property('bids[0]') + .with.property('params') + .to.have.property('adid', 'test-ad-83444226E44368D1E32E49EEBE6D29'); + expect(bidderRequest).to.have.deep.property('bids[0]') + .with.property('params') + .to.have.property('width', 300); + }); + + it('Valid bid-response', () => { + server.respondWith(JSON.stringify( + response + )); + adapterManager.callBids({ + adUnits: [clone(adUnit)] + }); + server.respond(); + + expect(bids).to.be.lengthOf(1); + expect(bids[0].getStatusCode()).to.equal(CONSTANTS.STATUS.GOOD); + expect(bids[0].bidderCode).to.equal('ucfunnel'); + expect(bids[0].width).to.equal(300); + expect(bids[0].height).to.equal(250); + expect(bids[0].cpm).to.equal(0.01); + }); + }); +}); + +function clone(obj) { + try { + return JSON.parse(JSON.stringify(obj)); + } catch (e) { + return {}; + } +} diff --git a/test/spec/adapters/underdogmedia_spec.js b/test/spec/modules/underdogmediaBidAdapter_spec.js similarity index 69% rename from test/spec/adapters/underdogmedia_spec.js rename to test/spec/modules/underdogmediaBidAdapter_spec.js index 3c8639fd56a..249111be6ea 100644 --- a/test/spec/adapters/underdogmedia_spec.js +++ b/test/spec/modules/underdogmediaBidAdapter_spec.js @@ -1,6 +1,4 @@ -/* jshint -W030 */ - -import Adapter from '../../../src/adapters/underdogmedia'; +import Adapter from '../../../modules/underdogmediaBidAdapter'; import bidManager from '../../../src/bidmanager'; import adloader from '../../../src/adloader'; @@ -9,7 +7,6 @@ import { } from 'chai'; describe('underdogmedia adapter test', () => { - let adapter; let server; @@ -18,55 +15,54 @@ describe('underdogmedia adapter test', () => { var bidderRequest = { bidderCode: 'underdogmedia', bids: [{ - bidder: 'underdogmedia', - adUnitCode: 'foo', - sizes: [ - [728, 90] - ], - params: { - siteId: '10272' - } - }, - { - bidder: 'underdogmedia', - adUnitCode: 'bar', - sizes: [ - [300, 250] - ], - params: { - siteId: '10272', - subId: 'TEST_SUBID' - } - }, - { - bidder: 'underdogmedia', - adUnitCode: 'nothing', - sizes: [160, 600], - params: { - siteId: '31337' - } + bidder: 'underdogmedia', + adUnitCode: 'foo', + sizes: [ + [728, 90] + ], + params: { + siteId: '10272' + } + }, + { + bidder: 'underdogmedia', + adUnitCode: 'bar', + sizes: [ + [300, 250] + ], + params: { + siteId: '10272', + subId: 'TEST_SUBID' } + }, + { + bidder: 'underdogmedia', + adUnitCode: 'nothing', + sizes: [160, 600], + params: { + siteId: '31337' + } + } ] }; var response = { - "mids": [{ - "width": 728, - "notification_url": "//udmserve.net/notification_url", - "height": 90, - "cpm": 2.5, - "ad_code_html": "Ad HTML for site ID 10272 size 728x90" - }, - { - "width": 300, - "notification_url": "//udmserve.net/notification_url", - "height": 250, - "cpm": 2.0, - "ad_code_html": "Ad HTML for site ID 10272 size 300x250" - } + 'mids': [{ + 'width': 728, + 'notification_url': '//udmserve.net/notification_url', + 'height': 90, + 'cpm': 2.5, + 'ad_code_html': 'Ad HTML for site ID 10272 size 728x90' + }, + { + 'width': 300, + 'notification_url': '//udmserve.net/notification_url', + 'height': 250, + 'cpm': 2.0, + 'ad_code_html': 'Ad HTML for site ID 10272 size 300x250' + } ] }; - beforeEach(() => { adapter = new Adapter(); }); @@ -74,7 +70,6 @@ describe('underdogmedia adapter test', () => { afterEach(() => {}); describe('adding bids to the manager', () => { - let firstBid; let secondBid; let thirdBid; @@ -100,14 +95,12 @@ describe('underdogmedia adapter test', () => { }); it('will add the ad html to the bid object', () => { - expect(firstBid).to.have.property('ad').includes('Ad HTML for site ID 10272 size 728x90'); expect(secondBid).to.have.property('ad').includes('Ad HTML for site ID 10272 size 300x250').and.includes('TEST_SUBID'); expect(thirdBid).to.not.have.property('ad'); }); it('will have the right size attached', () => { - expect(firstBid).to.have.property('width', 728); expect(firstBid).to.have.property('height', 90); expect(secondBid).to.have.property('width', 300); @@ -125,7 +118,5 @@ describe('underdogmedia adapter test', () => { expect(secondBid).to.have.property('bidderCode', 'underdogmedia'); expect(thirdBid).to.have.property('bidderCode', 'underdogmedia'); }); - }); - }); diff --git a/test/spec/modules/unrulyBidAdapter_spec.js b/test/spec/modules/unrulyBidAdapter_spec.js new file mode 100644 index 00000000000..dfa7a72b8ad --- /dev/null +++ b/test/spec/modules/unrulyBidAdapter_spec.js @@ -0,0 +1,278 @@ +/* globals describe, it, beforeEach, afterEach, sinon */ +import { expect } from 'chai' +import bidfactory from 'src/bidfactory' +import bidmanager from 'src/bidmanager' +import * as utils from 'src/utils' +import { STATUS } from 'src/constants' +import { Renderer } from 'src/Renderer' +import createUnrulyAdapter from 'modules/unrulyBidAdapter' + +describe('UnrulyAdapter', () => { + function createBidRequestBid({ placementCode }) { + return { + 'bidder': 'unruly', + 'params': { + 'uuid': '74544e00-d43b-4f3a-a799-69d22ce979ce', + 'siteId': 794599, + 'placementId': '5768085' + }, + 'placementCode': placementCode, + 'mediaType': 'video', + 'transactionId': '62890707-3770-497c-a3b8-d905a2d0cb98', + 'sizes': [ + 640, + 480 + ], + 'bidId': '23b86d8f6335ce', + 'bidderRequestId': '1d5b7474eb5416', + 'requestId': '406fe12b-fa3b-4bd3-b3c8-043951b4dac1' + } + } + + function createParams(...bids) { + return { + 'bidderCode': 'unruly', + 'requestId': '406fe12b-fa3b-4bd3-b3c8-043951b4dac1', + 'bidderRequestId': '1d5b7474eb5416', + 'bids': bids, + 'start': 1495794517251, + 'auctionStart': 1495794517250, + 'timeout': 3000 + } + } + + function createOutStreamExchangeBid({ placementCode, statusCode = 1 }) { + return { + 'ext': { + 'statusCode': statusCode, + 'renderer': { + 'id': 'unruly_inarticle', + 'config': {}, + 'url': 'https://video.unrulymedia.com/native/prebid-loader.js' + }, + 'placementCode': placementCode + }, + 'cpm': 20, + 'bidderCode': 'unruly', + 'width': 323, + 'vastUrl': 'https://targeting.unrulymedia.com/in_article?uuid=74544e00-d43b-4f3a-a799-69d22ce979ce&supported_mime_type=application/javascript&supported_mime_type=video/mp4&tj=%7B%22site%22%3A%7B%22lang%22%3A%22en-GB%22%2C%22ref%22%3A%22%22%2C%22page%22%3A%22http%3A%2F%2Fdemo.unrulymedia.com%2FinArticle%2Finarticle_nypost_upbeat%2Ftravel_magazines.html%22%2C%22domain%22%3A%22demo.unrulymedia.com%22%7D%2C%22user%22%3A%7B%22profile%22%3A%7B%22quantcast%22%3A%7B%22segments%22%3A%5B%7B%22id%22%3A%22D%22%7D%2C%7B%22id%22%3A%22T%22%7D%5D%7D%7D%7D%7D&video_width=618&video_height=347', + 'bidId': 'foo', + 'height': 323 + } + } + + function createInStreamExchangeBid({ placementCode, statusCode = 1 }) { + return { + 'ext': { + 'statusCode': statusCode, + 'placementCode': placementCode + }, + 'cpm': 20, + 'bidderCode': 'unruly', + 'width': 323, + 'vastUrl': 'https://targeting.unrulymedia.com/in_article?uuid=74544e00-d43b-4f3a-a799-69d22ce979ce&supported_mime_type=application/javascript&supported_mime_type=video/mp4&tj=%7B%22site%22%3A%7B%22lang%22%3A%22en-GB%22%2C%22ref%22%3A%22%22%2C%22page%22%3A%22http%3A%2F%2Fdemo.unrulymedia.com%2FinArticle%2Finarticle_nypost_upbeat%2Ftravel_magazines.html%22%2C%22domain%22%3A%22demo.unrulymedia.com%22%7D%2C%22user%22%3A%7B%22profile%22%3A%7B%22quantcast%22%3A%7B%22segments%22%3A%5B%7B%22id%22%3A%22D%22%7D%2C%7B%22id%22%3A%22T%22%7D%5D%7D%7D%7D%7D&video_width=618&video_height=347', + 'bidId': 'foo', + 'height': 323 + } + } + + function createExchangeResponse(...bids) { + return { + 'bids': bids + } + } + + let adapter + let server + let sandbox + let fakeRenderer + + beforeEach(() => { + adapter = createUnrulyAdapter() + adapter.exchangeUrl = 'http://localhost:9000/prebid' + + sandbox = sinon.sandbox.create() + sandbox.stub(bidmanager, 'addBidResponse') + sandbox.stub(bidfactory, 'createBid') + sandbox.stub(utils, 'logError') + + fakeRenderer = { + setRender: sinon.stub() + } + + sandbox.stub(Renderer, 'install') + Renderer.install.returns(fakeRenderer) + + server = sinon.fakeServer.create() + }) + + afterEach(() => { + sandbox.restore() + server.restore() + delete parent.window.unruly + }) + + describe('callBids', () => { + it('exists and is a function', () => { + expect(adapter.callBids).to.exist.and.to.be.a('function') + }) + + it('requires bids to make request', () => { + adapter.callBids({}) + expect(server.requests).to.be.empty + }) + + it('requires at least one bid to make request', () => { + adapter.callBids({ bids: [] }) + expect(server.requests).to.be.empty + }) + + it('passes bids through to exchange', () => { + const params = createParams(createBidRequestBid({ placementCode: 'placement1' })) + + adapter.callBids(params) + + expect(server.requests).to.have.length(1) + expect(server.requests[0].url).to.equal('http://localhost:9000/prebid') + + const requestBody = JSON.parse(server.requests[0].requestBody) + expect(requestBody).to.deep.equal({ + 'bidRequests': params.bids + }) + }) + + it('creates a bid response using status code from exchange for each bid and passes in the exchange response', () => { + const params = createParams(createBidRequestBid({ placementCode: 'placement1' })) + + const exchangeBid1 = createOutStreamExchangeBid({ placementCode: 'placement1' }) + const exchangeBid2 = createOutStreamExchangeBid({ placementCode: 'placement2', statusCode: 2 }) + const exchangeResponse = createExchangeResponse(exchangeBid1, exchangeBid2) + + server.respondWith(JSON.stringify(exchangeResponse)) + bidfactory.createBid.returns({}) + + adapter.callBids(params) + server.respond() + + sinon.assert.calledTwice(bidfactory.createBid) + sinon.assert.calledWith(bidfactory.createBid, exchangeBid1.ext.statusCode, exchangeResponse.bids[0]) + sinon.assert.calledWith(bidfactory.createBid, exchangeBid2.ext.statusCode, exchangeResponse.bids[1]) + }) + + it('adds the bid response to the bid manager', () => { + const fakeBid = {} + + const params = createParams(createBidRequestBid({ placementCode: 'placement1' })) + const exchangeBid = createOutStreamExchangeBid({ placementCode: 'placement1' }) + const exchangeResponse = createExchangeResponse(exchangeBid) + + server.respondWith(JSON.stringify(exchangeResponse)) + bidfactory.createBid.withArgs(exchangeBid.ext.statusCode).returns(fakeBid) + + adapter.callBids(params) + server.respond() + + sinon.assert.calledOnce(bidmanager.addBidResponse) + sinon.assert.calledWith(bidmanager.addBidResponse, exchangeBid.ext.placementCode, fakeBid) + }) + + describe('on invalid exchange response', () => { + it('should create NO_BID response for each bid request bid', () => { + const bidRequestBid1 = createBidRequestBid({ placementCode: 'placement1' }) + const bidRequestBid2 = createBidRequestBid({ placementCode: 'placement2' }) + const params = createParams(bidRequestBid1, bidRequestBid2) + const expectedBid = { 'some': 'props' } + + server.respondWith('this is not json') + bidfactory.createBid.withArgs(STATUS.NO_BID).returns(expectedBid) + + adapter.callBids(params) + server.respond() + + sinon.assert.calledOnce(utils.logError) + sinon.assert.calledTwice(bidmanager.addBidResponse) + sinon.assert.calledWith(bidmanager.addBidResponse, bidRequestBid1.placementCode, expectedBid) + sinon.assert.calledWith(bidmanager.addBidResponse, bidRequestBid2.placementCode, expectedBid) + }) + }) + + describe('InStream', () => { + it('merges bid response defaults', () => { + const params = createParams(createBidRequestBid({ placementCode: 'placement1' })) + + const fakeBidDefaults = { some: 'default' } + const fakeBid = Object.assign({}, fakeBidDefaults) + + const exchangeBid = createInStreamExchangeBid({ placementCode: 'placement1' }) + const exchangeResponse = createExchangeResponse(exchangeBid) + server.respondWith(JSON.stringify(exchangeResponse)) + + bidfactory.createBid.withArgs(exchangeBid.ext.statusCode).returns(fakeBid) + + adapter.callBids(params) + server.respond() + + sinon.assert.notCalled(Renderer.install) + expect(fakeBid).to.deep.equal(Object.assign( + {}, + fakeBidDefaults, + exchangeBid + )) + }) + }) + + describe('OutStream', () => { + it('merges bid response defaults with exchange bid and renderer', () => { + const params = createParams(createBidRequestBid({ placementCode: 'placement1' })) + + const fakeBidDefaults = { some: 'default' } + const fakeBid = Object.assign({}, fakeBidDefaults) + + const exchangeBid = createOutStreamExchangeBid({ placementCode: 'placement1' }) + const exchangeResponse = createExchangeResponse(exchangeBid) + server.respondWith(JSON.stringify(exchangeResponse)) + + bidfactory.createBid.withArgs(exchangeBid.ext.statusCode).returns(fakeBid) + + const fakeRenderer = {} + Renderer.install.withArgs(Object.assign( + {}, + exchangeBid.ext.renderer, + { callback: sinon.match.func } + )).returns(fakeRenderer) + + adapter.callBids(params) + server.respond() + + expect(fakeBid).to.deep.equal(Object.assign( + {}, + fakeBidDefaults, + exchangeBid, + { renderer: fakeRenderer } + )) + }) + + it('bid is placed on the bid queue when render is called', () => { + const params = createParams(createBidRequestBid({ placementCode: 'placement1' })) + + const fakeBidDefaults = { some: 'default' } + const fakeBid = Object.assign({}, fakeBidDefaults) + + const exchangeBid = createOutStreamExchangeBid({ placementCode: 'placement1' }) + const exchangeResponse = createExchangeResponse(exchangeBid) + server.respondWith(JSON.stringify(exchangeResponse)) + + bidfactory.createBid.withArgs(exchangeBid.ext.statusCode).returns(fakeBid) + + adapter.callBids(params) + server.respond() + + sinon.assert.calledOnce(fakeRenderer.setRender) + fakeRenderer.setRender.firstCall.args[0]() + + expect(window.top).to.have.deep.property('unruly.native.prebid.uq'); + expect(window.top.unruly.native.prebid.uq).to.deep.equal([['render', fakeBid]]) + }) + }) + }) +}) diff --git a/test/spec/modules/vertamediaBidAdapter_spec.js b/test/spec/modules/vertamediaBidAdapter_spec.js new file mode 100644 index 00000000000..3afe75790a5 --- /dev/null +++ b/test/spec/modules/vertamediaBidAdapter_spec.js @@ -0,0 +1,141 @@ +import { expect } from 'chai'; +import Adapter from 'modules/vertamediaBidAdapter'; +import bidmanager from 'src/bidmanager'; + +const ENDPOINT = 'http://rtb.vertamedia.com/hb/?aid=22489&w=640&h=480&domain=localhost'; + +const REQUEST = { + 'bidderCode': 'vertamedia', + 'requestId': 'd3e07445-ab06-44c8-a9dd-5ef9af06d2a6', + 'bidderRequestId': '7101db09af0db2', + 'bids': [ + { + 'bidder': 'vertamedia', + 'params': { + aid: 22489, + placementId: '123456' + }, + 'placementCode': '/19968336/header-bid-tag1', + 'sizes': [640, 480], + 'bidId': '84ab500420319d', + 'bidderRequestId': '7101db09af0db2', + 'requestId': 'd3e07445-ab06-44c8-a9dd-5ef9af06d2a6' + } + ], + 'start': 1469479810130 +}; +var RESPONSE = { + 'source': { + 'aid': 22489, + 'pubId': 18016, + 'sid': '0' + }, + 'bids': [ + { + 'cmpId': 9541, + 'cpm': 4.5, + 'url': 'http://rtb.vertamedia.com/vast?adid=BFDB9CC0038AD918', + 'cur': 'USD' + } + ] +}; + +describe('VertamediaAdater', () => { + let adapter; + + beforeEach(() => adapter = Adapter.createNew()); + + describe('request function', () => { + let xhr; + let requests; + + beforeEach(() => { + xhr = sinon.useFakeXMLHttpRequest(); + requests = []; + xhr.onCreate = request => requests.push(request); + }); + + afterEach(() => xhr.restore()); + + it('exists and is a function', () => { + expect(adapter.callBids).to.exist.and.to.be.a('function'); + }); + + it('requires paramters to make request', () => { + adapter.callBids({}); + expect(requests).to.be.empty; + }); + + it('requires member && invCode', () => { + let backup = REQUEST.bids[0].params; + REQUEST.bids[0].params = {member: 1234}; + adapter.callBids(REQUEST); + expect(requests).to.be.empty; + REQUEST.bids[0].params = backup; + }); + + it('sends bid request to ENDPOINT via POST', () => { + adapter.callBids(REQUEST); + expect(requests[0].url).to.equal(ENDPOINT); + expect(requests[0].method).to.equal('GET'); + }); + }); + + describe('response handler', () => { + let server; + + beforeEach(() => { + server = sinon.fakeServer.create(); + sinon.stub(bidmanager, 'addBidResponse'); + }); + + afterEach(() => { + server.restore(); + bidmanager.addBidResponse.restore(); + }); + + it('registers bids', () => { + server.respondWith(JSON.stringify(RESPONSE)); + + adapter.callBids(REQUEST); + server.respond(); + sinon.assert.calledOnce(bidmanager.addBidResponse); + + const response = bidmanager.addBidResponse.firstCall.args[1]; + expect(response).to.have.property('statusMessage', 'Bid available'); + expect(response).to.have.property('cpm', 4.5); + }); + + it('handles nobid responses', () => { + server.respondWith(JSON.stringify({ + aid: 356465468, + w: 640, + h: 480, + domain: 'localhost' + })); + + adapter.callBids(REQUEST); + server.respond(); + sinon.assert.calledOnce(bidmanager.addBidResponse); + + const response = bidmanager.addBidResponse.firstCall.args[1]; + expect(response).to.have.property( + 'statusMessage', + 'Bid returned empty or error response' + ); + }); + + it('handles JSON.parse errors', () => { + server.respondWith(''); + + adapter.callBids(REQUEST); + server.respond(); + sinon.assert.calledOnce(bidmanager.addBidResponse); + + expect(bidmanager.addBidResponse.firstCall.args[1]).to.have.property( + 'statusMessage', + 'Bid returned empty or error response' + ); + }); + }); +}); diff --git a/test/spec/modules/vertozBidAdapter_spec.js b/test/spec/modules/vertozBidAdapter_spec.js new file mode 100755 index 00000000000..87d0ec8c842 --- /dev/null +++ b/test/spec/modules/vertozBidAdapter_spec.js @@ -0,0 +1,140 @@ +import {expect} from 'chai'; +import {assert} from 'chai'; +import Adapter from '../../../modules/vertozBidAdapter'; +import bidManager from '../../../src/bidmanager'; +import adLoader from '../../../src/adloader'; + +describe('Vertoz Adapter', () => { + let adapter; + let sandbox; + let bidsRequestBuff; + const bidderRequest = { + bidderCode: 'vertoz', + bids: [{ + bidId: 'bidId1', + bidder: 'vertoz', + placementCode: 'foo', + sizes: [ + [300, 250] + ], + params: { + placementId: 'VZ-HB-123' + } + }, { + bidId: 'bidId2', + bidder: 'vertoz', + placementCode: 'bar', + sizes: [ + [728, 90] + ], + params: { + placementId: 'VZ-HB-456' + } + }, { + bidId: 'bidId3', + bidder: 'vertoz', + placementCode: 'coo', + sizes: [ + [300, 600] + ], + params: { + placementId: '' + } + }] + }; + + beforeEach(() => { + adapter = new Adapter(); + sandbox = sinon.sandbox.create(); + bidsRequestBuff = $$PREBID_GLOBAL$$._bidsRequested; + $$PREBID_GLOBAL$$._bidsRequested = []; + }); + + afterEach(() => { + sandbox.restore(); + $$PREBID_GLOBAL$$._bidsRequested = bidsRequestBuff; + }); + + describe('callBids', () => { + beforeEach(() => { + sandbox.stub(adLoader, 'loadScript'); + adapter.callBids(bidderRequest); + }); + + it('should be called twice', () => { + sinon.assert.calledTwice(adLoader.loadScript); + }); + }); + + describe('Bid response', () => { + let vzBidRequest; + let bidderReponse = { + 'vzhPlacementId': 'VZ-HB-123', + 'bid': '0fac1b8a-6ba0-4641-bd57-2899b1bedeae_0', + 'adWidth': '300', + 'adHeight': '250', + 'cpm': '1.00000000000000', + 'ad': '
', + 'slotBidId': 'bidId1', + 'nurl': '', + 'statusText': 'vertoz:success' + }; + + beforeEach(() => { + $$PREBID_GLOBAL$$._bidsRequested.push(bidderRequest); + }); + + describe('success', () => { + let firstBidReg; + let adSpaceId; + + beforeEach(() => { + sandbox.stub(bidManager, 'addBidResponse'); + $$PREBID_GLOBAL$$.vzResponse(bidderReponse); + firstBidReg = bidManager.addBidResponse.firstCall.args[1]; + adSpaceId = bidManager.addBidResponse.firstCall.args[0]; + }); + + it('cpm to have property 1.000000', () => { + expect(firstBidReg).to.have.property('cpm', 1.00); + }); + it('adSpaceId should exist and be equal to placementCode', () => { + expect(adSpaceId).to.equal('foo'); + }); + it('should have property ad', () => { + expect(firstBidReg).to.have.property('ad'); + }); + it('should include the size to the bid object', () => { + expect(firstBidReg).to.have.property('width', '300'); + expect(firstBidReg).to.have.property('height', '250'); + }); + }); + + describe('failure', () => { + let secondBidReg; + let adSpaceId; + let bidderResponse = { + 'vzhPlacementId': 'VZ-HB-456', + 'slotBidId': 'bidId2', + 'statusText': 'vertoz:NO_BIDS' + } + + beforeEach(() => { + sandbox.stub(bidManager, 'addBidResponse'); + $$PREBID_GLOBAL$$.vzResponse(bidderResponse); + secondBidReg = bidManager.addBidResponse.firstCall.args[1]; + adSpaceId = bidManager.addBidResponse.firstCall.args[0]; + }); + + it('should not have cpm property', () => { + expect(secondBidReg.cpm).to.be.undefined; + }); + it('adSpaceId should exist and be equal to placementCode', () => { + expect(adSpaceId).to.equal('bar'); + }); + it('should not have ad property', () => { + expect(secondBidReg.ad).to.be.undefined; + }); + }); + }); +}); diff --git a/test/spec/modules/wideorbitBidAdapter_spec.js b/test/spec/modules/wideorbitBidAdapter_spec.js new file mode 100644 index 00000000000..9ace04883e6 --- /dev/null +++ b/test/spec/modules/wideorbitBidAdapter_spec.js @@ -0,0 +1,497 @@ +describe('wideorbit adapter tests', function () { + var expect = require('chai').expect; + var urlParse = require('url-parse'); + + // FYI: querystringify will perform encoding/decoding + var querystringify = require('querystringify'); + + var adapter = require('modules/wideorbitBidAdapter'); + var adLoader = require('src/adloader'); + var bidmanager = require('src/bidmanager'); + + describe('creation of bid url', function () { + let stubLoadScript; + + beforeEach(function () { + stubLoadScript = sinon.stub(adLoader, 'loadScript'); + }); + + afterEach(function () { + stubLoadScript.restore(); + }); + + it('should be called only once', function () { + var params = { + bidderCode: 'wideorbit', + bids: [ + { + bidder: 'wideorbit', + params: { + pbId: 1, + pId: 101 + }, + placementCode: 'div-gpt-ad-12345-1' + }, + { + bidder: 'wideorbit', + params: { + pbId: 1, + site: 'Site 1', + page: 'Page 1', + width: 100, + height: 200, + subPublisher: 'Sub Publisher 1' + }, + placementCode: 'div-gpt-ad-12345-2' + } + ] + }; + + adapter().callBids(params); + + sinon.assert.calledOnce(stubLoadScript); + }); + + it('should fix parameters name', function () { + var params = { + bidderCode: 'wideorbit', + bids: [ + { + bidder: 'wideorbit', + params: { + PBiD: 1, + PID: 101, + ReferRer: 'http://www.foo.com?param1=param1¶m2=param2' + }, + placementCode: 'div-gpt-ad-12345-1' + }, + { + bidder: 'wideorbit', + params: { + pbid: 1, + SiTe: 'Site 1', + Page: 'Page 1', + widTH: 100, + HEIGHT: 200, + SUBPublisher: 'Sub Publisher 1' + }, + placementCode: 'div-gpt-ad-12345-2' + } + ] + }; + + adapter().callBids(params); + + var bidUrl = stubLoadScript.getCall(0).args[0]; + + sinon.assert.calledWith(stubLoadScript, bidUrl); + + var parsedBidUrl = urlParse(bidUrl); + var parsedBidUrlQueryString = querystringify.parse(parsedBidUrl.query); + + expect(parsedBidUrl.hostname).to.equal('p1.atemda.com') + expect(parsedBidUrl.pathname).to.equal('/JSAdservingMP.ashx') + expect(parsedBidUrlQueryString).to.have.property('pc').and.to.equal('2'); + expect(parsedBidUrlQueryString).to.have.property('pbId').and.to.equal('1'); + expect(parsedBidUrlQueryString).to.have.property('jsv').and.to.equal('1.0'); + expect(parsedBidUrlQueryString).to.have.property('tsv').and.to.equal('1.0'); + expect(parsedBidUrlQueryString).to.have.property('cts').to.have.length.above(0); + expect(parsedBidUrlQueryString).to.have.property('arp').and.to.equal('0'); + expect(parsedBidUrlQueryString).to.have.property('fl').and.to.equal('0'); + expect(parsedBidUrlQueryString).to.have.property('jscb').and.to.equal('window.$$PREBID_GLOBAL$$.handleWideOrbitCallback'); + expect(parsedBidUrlQueryString).to.have.property('mpp').and.to.equal('0'); + expect(parsedBidUrlQueryString).to.have.property('cb').to.have.length.above(0); + expect(parsedBidUrlQueryString).to.have.property('hb').and.to.equal('1'); + expect(parsedBidUrlQueryString).to.have.property('url').and.to.equal('http://www.foo.com?param1=param1¶m2=param2'); + + expect(parsedBidUrlQueryString).to.have.property('gid0').and.to.equal('div-gpt-ad-12345-1'); + expect(parsedBidUrlQueryString).to.have.property('rpos0').and.to.equal('0'); + expect(parsedBidUrlQueryString).to.have.property('ecpm0').and.to.equal(''); + + expect(parsedBidUrlQueryString).to.have.property('gid1').and.to.equal('div-gpt-ad-12345-2'); + expect(parsedBidUrlQueryString).to.have.property('rpos1').and.to.equal('0'); + expect(parsedBidUrlQueryString).to.have.property('ecpm1').and.to.equal(''); + + expect(parsedBidUrlQueryString).to.have.property('pId0').and.to.equal('101'); + expect(parsedBidUrlQueryString).to.have.property('rank0').and.to.equal('0'); + + expect(parsedBidUrlQueryString).to.have.property('wsName1').and.to.equal('Site 1'); + expect(parsedBidUrlQueryString).to.have.property('wName1').and.to.equal('Page 1'); + expect(parsedBidUrlQueryString).to.have.property('rank1').and.to.equal('1'); + expect(parsedBidUrlQueryString).to.have.property('bfDim1').and.to.equal('100x200'); + expect(parsedBidUrlQueryString).to.have.property('subp1').and.to.equal('Sub Publisher 1'); + }); + + describe('placement by name', function () { + it('should be called with specific parameters for two bids', function () { + var params = { + bidderCode: 'wideorbit', + bids: [ + { + bidder: 'wideorbit', + params: { + pbId: 1, + site: 'Site 1', + page: 'Page 1', + width: 100, + height: 200, + subPublisher: 'Sub Publisher 1', + atf: true + }, + placementCode: 'div-gpt-ad-12345-1' + }, + { + bidder: 'wideorbit', + params: { + pbId: 1, + site: 'Site 2', + page: 'Page 2', + width: 200, + height: 300, + rank: 123, + ecpm: 1.8 + }, + placementCode: 'div-gpt-ad-12345-2' + } + ] + }; + + adapter().callBids(params); + + var bidUrl = stubLoadScript.getCall(0).args[0]; + + sinon.assert.calledWith(stubLoadScript, bidUrl); + + var parsedBidUrl = urlParse(bidUrl); + var parsedBidUrlQueryString = querystringify.parse(parsedBidUrl.query); + + expect(parsedBidUrl.hostname).to.equal('p1.atemda.com') + expect(parsedBidUrl.pathname).to.equal('/JSAdservingMP.ashx') + expect(parsedBidUrlQueryString).to.have.property('pc').and.to.equal('2'); + expect(parsedBidUrlQueryString).to.have.property('pbId').and.to.equal('1'); + expect(parsedBidUrlQueryString).to.have.property('jsv').and.to.equal('1.0'); + expect(parsedBidUrlQueryString).to.have.property('tsv').and.to.equal('1.0'); + expect(parsedBidUrlQueryString).to.have.property('cts').to.have.length.above(0); + expect(parsedBidUrlQueryString).to.have.property('arp').and.to.equal('0'); + expect(parsedBidUrlQueryString).to.have.property('fl').and.to.equal('0'); + expect(parsedBidUrlQueryString).to.have.property('jscb').and.to.equal('window.$$PREBID_GLOBAL$$.handleWideOrbitCallback'); + expect(parsedBidUrlQueryString).to.have.property('mpp').and.to.equal('0'); + expect(parsedBidUrlQueryString).to.have.property('cb').to.have.length.above(0); + expect(parsedBidUrlQueryString).to.have.property('hb').and.to.equal('1'); + expect(parsedBidUrlQueryString).to.have.property('url').and.to.be.empty; + + expect(parsedBidUrlQueryString).to.have.property('gid0').and.to.equal('div-gpt-ad-12345-1'); + expect(parsedBidUrlQueryString).to.have.property('rpos0').and.to.equal('1001'); + expect(parsedBidUrlQueryString).to.have.property('ecpm0').and.to.equal(''); + + expect(parsedBidUrlQueryString).to.have.property('gid1').and.to.equal('div-gpt-ad-12345-2'); + expect(parsedBidUrlQueryString).to.have.property('rpos1').and.to.equal('0'); + expect(parsedBidUrlQueryString).to.have.property('ecpm1').and.to.equal('1.8'); + + expect(parsedBidUrlQueryString).to.have.property('wsName0').and.to.equal('Site 1'); + expect(parsedBidUrlQueryString).to.have.property('wName0').and.to.equal('Page 1'); + expect(parsedBidUrlQueryString).to.have.property('rank0').and.to.equal('0'); + expect(parsedBidUrlQueryString).to.have.property('bfDim0').and.to.equal('100x200'); + expect(parsedBidUrlQueryString).to.have.property('subp0').and.to.equal('Sub Publisher 1'); + + expect(parsedBidUrlQueryString).to.have.property('wsName1').and.to.equal('Site 2'); + expect(parsedBidUrlQueryString).to.have.property('wName1').and.to.equal('Page 2'); + expect(parsedBidUrlQueryString).to.have.property('rank1').and.to.equal('123'); + expect(parsedBidUrlQueryString).to.have.property('bfDim1').and.to.equal('200x300'); + expect(parsedBidUrlQueryString).to.have.property('subp1').and.to.equal(''); + }); + }); + + describe('placement by id', function () { + it('should be called with specific parameters for two bids', function () { + var params = { + bidderCode: 'wideorbit', + bids: [ + { + bidder: 'wideorbit', + params: { + pbId: 1, + pId: 101, + atf: true, + ecpm: 0.8 + }, + placementCode: 'div-gpt-ad-12345-1' + }, + { + bidder: 'wideorbit', + params: { + pbId: 1, + pId: 102, + rank: 123 + }, + placementCode: 'div-gpt-ad-12345-2' + } + ] + }; + + adapter().callBids(params); + + var bidUrl = stubLoadScript.getCall(0).args[0]; + + sinon.assert.calledWith(stubLoadScript, bidUrl); + + var parsedBidUrl = urlParse(bidUrl); + var parsedBidUrlQueryString = querystringify.parse(parsedBidUrl.query); + + expect(parsedBidUrl.hostname).to.equal('p1.atemda.com') + expect(parsedBidUrl.pathname).to.equal('/JSAdservingMP.ashx') + expect(parsedBidUrlQueryString).to.have.property('pc').and.to.equal('2'); + expect(parsedBidUrlQueryString).to.have.property('pbId').and.to.equal('1'); + expect(parsedBidUrlQueryString).to.have.property('jsv').and.to.equal('1.0'); + expect(parsedBidUrlQueryString).to.have.property('tsv').and.to.equal('1.0'); + expect(parsedBidUrlQueryString).to.have.property('cts').to.have.length.above(0); + expect(parsedBidUrlQueryString).to.have.property('arp').and.to.equal('0'); + expect(parsedBidUrlQueryString).to.have.property('fl').and.to.equal('0'); + expect(parsedBidUrlQueryString).to.have.property('jscb').and.to.equal('window.$$PREBID_GLOBAL$$.handleWideOrbitCallback'); + expect(parsedBidUrlQueryString).to.have.property('mpp').and.to.equal('0'); + expect(parsedBidUrlQueryString).to.have.property('cb').to.have.length.above(0); + expect(parsedBidUrlQueryString).to.have.property('hb').and.to.equal('1'); + expect(parsedBidUrlQueryString).to.have.property('url').and.to.be.empty; + + expect(parsedBidUrlQueryString).to.have.property('gid0').and.to.equal('div-gpt-ad-12345-1'); + expect(parsedBidUrlQueryString).to.have.property('rpos0').and.to.equal('1001'); + expect(parsedBidUrlQueryString).to.have.property('ecpm0').and.to.equal('0.8'); + + expect(parsedBidUrlQueryString).to.have.property('gid1').and.to.equal('div-gpt-ad-12345-2'); + expect(parsedBidUrlQueryString).to.have.property('rpos1').and.to.equal('0'); + expect(parsedBidUrlQueryString).to.have.property('ecpm1').and.to.equal(''); + + expect(parsedBidUrlQueryString).to.have.property('pId0').and.to.equal('101'); + expect(parsedBidUrlQueryString).to.have.property('rank0').and.to.equal('0'); + + expect(parsedBidUrlQueryString).to.have.property('pId1').and.to.equal('102'); + expect(parsedBidUrlQueryString).to.have.property('rank1').and.to.equal('123'); + }); + }); + }); + + // describe('handling of the callback response', function () { + // + // var placements = [ + // { + // ExtPlacementId: 'div-gpt-ad-12345-1', + // Type: 'DirectHTML', + // Bid: 1.3, + // Width: 50, + // Height: 100, + // Source: '
The AD 1 itself...
', + // TrackingCodes: [ + // 'https://www.admeta.com/1.gif' + // ] + // }, + // { + // ExtPlacementId: 'div-gpt-ad-12345-2', + // Type: 'DirectHTML', + // Bid: 1.5, + // Width: 100, + // Height: 200, + // Source: '
The AD 2 itself...
', + // TrackingCodes: [ + // 'http://www.admeta.com/2a.gif', + // '' + // ] + // }, + // { + // ExtPlacementId: 'div-gpt-ad-12345-3', + // Type: 'Other', + // Bid: 1.7, + // Width: 150, + // Height: 250, + // Source: '
The AD 3 itself...
', + // TrackingCodes: [ + // 'http://www.admeta.com/3.gif' + // ] + // } + // ]; + // + // it('callback function should exist', function () { + // expect($$PREBID_GLOBAL$$.handleWideOrbitCallback).to.exist.and.to.be.a('function'); + // }); + // + // it('bidmanager.addBidResponse should be called thrice with correct arguments', function () { + // + // var stubAddBidResponse = sinon.stub(bidmanager, 'addBidResponse'); + // + // var params = { + // bidderCode: 'wideorbit', + // bids: [ + // { + // bidder: 'wideorbit', + // params: { + // pbId: 1, + // pId: 101 + // }, + // placementCode: 'div-gpt-ad-12345-1' + // }, + // { + // bidder: 'wideorbit', + // params: { + // pbId: 1, + // site: 'Site 1', + // page: 'Page 1', + // width: 100, + // height: 200, + // subPublisher: 'Sub Publisher 1' + // }, + // placementCode: 'div-gpt-ad-12345-2' + // }, + // { + // bidder: 'wideorbit', + // params: { + // pbId: 1, + // pId: 102 + // }, + // placementCode: 'div-gpt-ad-12345-3' + // }, + // ] + // }; + // + // var response = { + // UserMatchings: [ + // { + // Type: 'redirect', + // Url: 'http%3A%2F%2Fwww.admeta.com%2F1.gif' + // } + // ], + // Placements: placements + // }; + // + // adapter().callBids(params); + // $$PREBID_GLOBAL$$.handleWideOrbitCallback(response); + // + // var bidPlacementCode1 = stubAddBidResponse.getCall(0).args[0]; + // var bidObject1 = stubAddBidResponse.getCall(0).args[1]; + // var bidPlacementCode2 = stubAddBidResponse.getCall(1).args[0]; + // var bidObject2 = stubAddBidResponse.getCall(1).args[1]; + // var bidPlacementCode3 = stubAddBidResponse.getCall(2).args[0]; + // var bidObject3 = stubAddBidResponse.getCall(2).args[1]; + // + // expect(bidPlacementCode1).to.equal('div-gpt-ad-12345-1'); + // expect(bidObject1.cpm).to.equal(1.3); + // expect(bidObject1.ad).to.equal('
The AD 1 itself...
'); + // expect(bidObject1.width).to.equal(50); + // expect(bidObject1.height).to.equal(100); + // expect(bidObject1.getStatusCode()).to.equal(1); + // expect(bidObject1.bidderCode).to.equal('wideorbit'); + // + // expect(bidPlacementCode2).to.equal('div-gpt-ad-12345-2'); + // expect(bidObject2.cpm).to.equal(1.50); + // expect(bidObject2.ad).to.equal('
The AD 2 itself...
'); + // expect(bidObject2.width).to.equal(100); + // expect(bidObject2.height).to.equal(200); + // expect(bidObject2.getStatusCode()).to.equal(1); + // expect(bidObject2.bidderCode).to.equal('wideorbit'); + // + // expect(bidPlacementCode3).to.equal('div-gpt-ad-12345-3'); + // expect(bidObject3.getStatusCode()).to.equal(2); + // expect(bidObject3.bidderCode).to.equal('wideorbit'); + // + // sinon.assert.calledWith(stubAddBidResponse, bidPlacementCode1, bidObject1); + // sinon.assert.calledWith(stubAddBidResponse, bidPlacementCode2, bidObject2); + // sinon.assert.calledWith(stubAddBidResponse, bidPlacementCode3, bidObject3); + // + // sinon.assert.calledThrice(stubAddBidResponse); + // + // stubAddBidResponse.restore(); + // + // }); + // + // it('should append an image to the head when type is set to redirect', function () { + // + // var stubAddBidResponse = sinon.stub(bidmanager, 'addBidResponse'); + // + // var response = { + // UserMatchings: [ + // { + // Type: 'redirect', + // Url: 'http%3A%2F%2Fwww.admeta.com%2F1.gif' + // } + // ], + // Placements: placements + // }; + // + // $$PREBID_GLOBAL$$.handleWideOrbitCallback(response); + // + // var imgElement = document.querySelectorAll("head img")[0]; + // + // expect(imgElement).to.exist; + // expect(imgElement.src).to.equal('http://www.admeta.com/1.gif'); + // + // stubAddBidResponse.restore(); + // }); + // + // it('should append an iframe to the head when type is set to iframe', function () { + // + // var stubAddBidResponse = sinon.stub(bidmanager, 'addBidResponse'); + // + // var response = { + // UserMatchings: [ + // { + // Type: 'iframe', + // Url: 'http%3A%2F%2Fwww.admeta.com%2F1.ashx' + // } + // ], + // Placements: placements + // }; + // + // $$PREBID_GLOBAL$$.handleWideOrbitCallback(response); + // + // var iframeElement = document.querySelectorAll("head iframe")[0]; + // + // expect(iframeElement).to.exist; + // expect(iframeElement.src).to.equal('http://www.admeta.com/1.ashx'); + // + // stubAddBidResponse.restore(); + // + // }); + // + // it('should append an script to the head when type is set to js', function () { + // + // var stubAddBidResponse = sinon.stub(bidmanager, 'addBidResponse'); + // + // var response = { + // UserMatchings: [ + // { + // Type: 'js', + // Url: 'http%3A%2F%2Fwww.admeta.com%2F1.js' + // } + // ], + // Placements: placements + // }; + // + // $$PREBID_GLOBAL$$.handleWideOrbitCallback(response); + // + // var scriptElement = document.querySelectorAll("head script")[0]; + // + // expect(scriptElement).to.exist; + // expect(scriptElement.src).to.equal('http://www.admeta.com/1.js'); + // + // stubAddBidResponse.restore(); + // }); + // + // it('should do nothing when type is set to unrecognized type', function () { + // + // var stubAddBidResponse = sinon.stub(bidmanager, 'addBidResponse'); + // + // var response = { + // UserMatchings: [ + // { + // Type: 'unrecognized', + // Url: 'http%3A%2F%2Fwww.admeta.com%2F1.js' + // } + // ], + // Placements: placements + // }; + // + // $$PREBID_GLOBAL$$.handleWideOrbitCallback(response); + // + // stubAddBidResponse.restore(); + // }); + // + // }); +}); diff --git a/test/spec/adapters/widespace_spec.js b/test/spec/modules/widespaceBidAdapter_spec.js similarity index 64% rename from test/spec/adapters/widespace_spec.js rename to test/spec/modules/widespaceBidAdapter_spec.js index 51e8254ffcd..8b9d89a914c 100644 --- a/test/spec/adapters/widespace_spec.js +++ b/test/spec/modules/widespaceBidAdapter_spec.js @@ -1,74 +1,70 @@ import { expect } from 'chai'; import adLoader from '../../../src/adloader'; import bidManager from '../../../src/bidmanager'; -import Adapter from '../../../src/adapters/widespace'; - +import Adapter from '../../../modules/widespaceBidAdapter'; const ENDPOINT = '//engine.widespace.com/map/engine/hb/dynamic'; - const TEST = { - BIDDER_CODE: 'widespace', - CPM: 2.0, - PLACEMENT_CODE: 'aPlacementCode', - SID: 'f666bfaf-69cf-4ed9-9262-08247bb274e4', - CUR: 'EUR' - }; - - const BID_REQUEST = { - "bidderCode": TEST.BIDDER_CODE, - "requestId": "e155185b-3eac-4f3c-8182-cdb57a69df3c", - "bidderRequestId": "38993e482321e7", - "bids": [ - { - "bidder": TEST.BIDDER_CODE, - "params": { - "sid": TEST.SID, - "cur": TEST.CUR - }, - "placementCode": TEST.PLACEMENT_CODE, - "sizes": [ - [320, 320], - [320, 250] - ], - "bidId": "45c7f5afb996c1", - "bidderRequestId": "7101db09af0db3", - "requestId": "e155185b-3eac-4f3c-8182-cdb57a69df3d" - } - ], - "start": 1479664180396, - "timeout": 5000 - }; - - - const BID_RESPONSE = [{ - "status": "ok", - "reqId": "140590112507", - "adId": 13963, - "width": 320, - "height": 320, - "cpm": 2.0, - "currency": "EUR", - "code": "

This is a banner

", - "callbackUid": "45c7f5afb996c1", - "callback": "pbjs.widespaceHandleCB" - }]; - - const BID_NOAD_RESPONSE = [{ - "status": "noad", - "reqId": "143509454349", - "adId": 22, - "width": 1, - "height": 1, - "cpm": 0.0, - "currency": "EUR", - "code": "", - "callbackUid": "45c7f5afb996c1", - "callback": "pbjs.widespaceHandleCB" +const TEST = { + BIDDER_CODE: 'widespace', + CPM: 2.0, + PLACEMENT_CODE: 'aPlacementCode', + SID: 'f666bfaf-69cf-4ed9-9262-08247bb274e4', + CUR: 'EUR' +}; + +const BID_REQUEST = { + 'bidderCode': TEST.BIDDER_CODE, + 'requestId': 'e155185b-3eac-4f3c-8182-cdb57a69df3c', + 'bidderRequestId': '38993e482321e7', + 'bids': [ + { + 'bidder': TEST.BIDDER_CODE, + 'params': { + 'sid': TEST.SID, + 'cur': TEST.CUR + }, + 'placementCode': TEST.PLACEMENT_CODE, + 'sizes': [ + [320, 320], + [320, 250] + ], + 'bidId': '45c7f5afb996c1', + 'bidderRequestId': '7101db09af0db3', + 'requestId': 'e155185b-3eac-4f3c-8182-cdb57a69df3d' + } + ], + 'start': 1479664180396, + 'timeout': 5000 +}; + +const BID_RESPONSE = [{ + 'status': 'ok', + 'reqId': '140590112507', + 'adId': 13963, + 'width': 320, + 'height': 320, + 'cpm': 2.0, + 'currency': 'EUR', + 'code': '

This is a banner

', + 'callbackUid': '45c7f5afb996c1', + 'callback': 'pbjs.widespaceHandleCB' +}]; + +const BID_NOAD_RESPONSE = [{ + 'status': 'noad', + 'reqId': '143509454349', + 'adId': 22, + 'width': 1, + 'height': 1, + 'cpm': 0.0, + 'currency': 'EUR', + 'code': '', + 'callbackUid': '45c7f5afb996c1', + 'callback': 'pbjs.widespaceHandleCB' }] - describe('WidespaceAdapter', () => { - let adapter; let sandbox; @@ -81,13 +77,11 @@ describe('WidespaceAdapter', () => { sandbox.restore(); }); - describe('callBids', () => { it('should exists and be a function', () => { expect(adapter.callBids).to.exist.and.to.be.a('function'); }); - describe('with valid request parameters', () => { beforeEach(() => { sandbox.stub(adLoader, 'loadScript'); @@ -122,28 +116,26 @@ describe('WidespaceAdapter', () => { }); }); - describe('widespaceHandleCB', () => { it('should exist and be a function', () => { - expect(pbjs.widespaceHandleCB).to.exist.and.to.be.a('function'); + expect($$PREBID_GLOBAL$$.widespaceHandleCB).to.exist.and.to.be.a('function'); }); }); describe('respond with a successful bid', () => { let successfulBid, - placementCode; + placementCode; beforeEach(() => { sandbox.stub(bidManager, 'addBidResponse'); sandbox.stub(adLoader, 'loadScript'); adapter.callBids(BID_REQUEST); - pbjs._bidsRequested.push(BID_REQUEST); - pbjs.widespaceHandleCB(BID_RESPONSE); + $$PREBID_GLOBAL$$._bidsRequested.push(BID_REQUEST); + $$PREBID_GLOBAL$$.widespaceHandleCB(BID_RESPONSE); successfulBid = bidManager.addBidResponse.firstCall.args[1]; placementCode = bidManager.addBidResponse.firstCall.args[0]; - }); it('should add one bid', () => { @@ -159,9 +151,8 @@ describe('WidespaceAdapter', () => { }); it('should have a valid size', () => { - const bidSize = [successfulBid.width,successfulBid.height] + const bidSize = [successfulBid.width, successfulBid.height] expect(bidSize).to.eql(BID_REQUEST.bids[0].sizes[0]); - }); it('should recive right placementCode', () => { @@ -169,7 +160,6 @@ describe('WidespaceAdapter', () => { }); }); - describe('respond with a no-ad', () => { let noadBid; @@ -178,8 +168,8 @@ describe('WidespaceAdapter', () => { sandbox.stub(adLoader, 'loadScript'); adapter.callBids(BID_REQUEST); - pbjs._bidsRequested.push(BID_REQUEST); - pbjs.widespaceHandleCB(BID_NOAD_RESPONSE); + $$PREBID_GLOBAL$$._bidsRequested.push(BID_REQUEST); + $$PREBID_GLOBAL$$.widespaceHandleCB(BID_NOAD_RESPONSE); noadBid = bidManager.addBidResponse.firstCall.args[1]; }); @@ -188,7 +178,4 @@ describe('WidespaceAdapter', () => { expect(noadBid.getStatusCode()).to.eql(2); }); }); - - - }); diff --git a/test/spec/adapters/yieldbot_spec.js b/test/spec/modules/yieldbotBidAdapter_spec.js similarity index 66% rename from test/spec/adapters/yieldbot_spec.js rename to test/spec/modules/yieldbotBidAdapter_spec.js index 19de14380df..006eb4bbf98 100644 --- a/test/spec/adapters/yieldbot_spec.js +++ b/test/spec/modules/yieldbotBidAdapter_spec.js @@ -1,5 +1,5 @@ import {expect} from 'chai'; -import YieldbotAdapter from 'src/adapters/yieldbot'; +import YieldbotAdapter from 'modules/yieldbotBidAdapter'; import bidManager from 'src/bidmanager'; import adLoader from 'src/adloader'; @@ -42,7 +42,6 @@ const YB_BID_FIXTURE = { }; function createYieldbotMockLib() { - // jshint unused:false window.yieldbot = { _initialized: false, pub: (psn) => {}, @@ -51,17 +50,16 @@ function createYieldbotMockLib() { go: () => { window.yieldbot._initialized = true; }, nextPageview: (slots, callback) => {}, getSlotCriteria: (slotName) => { - return YB_BID_FIXTURE[slotName] || {ybot_ad: "n"}; + return YB_BID_FIXTURE[slotName] || {ybot_ad: 'n'}; } }; - // jshint unused:true } function restoreYieldbotMockLib() { window.yieldbot = null; } -function mockYieldbotInitBidRequest() { +function mockYieldbotBidRequest() { window.ybotq = window.ybotq || []; window.ybotq.forEach(fn => { fn.apply(window.yieldbot); @@ -73,33 +71,39 @@ let sandbox; let bidManagerStub; let yieldbotLibStub; -before(function() { - window.pbjs._bidsRequested.push(bidderRequest); +beforeEach(function() { + window.$$PREBID_GLOBAL$$._bidsRequested.push(bidderRequest); }); -describe('Yieldbot adapter tests', function() { +function setupTest() { + sandbox = sinon.sandbox.create(); - describe('callBids', function() { - beforeEach(function () { + createYieldbotMockLib(); - sandbox = sinon.sandbox.create(); + sandbox.stub(adLoader, 'loadScript'); + yieldbotLibStub = sandbox.stub(window.yieldbot); + yieldbotLibStub.getSlotCriteria.restore(); - createYieldbotMockLib(); + bidManagerStub = sandbox.stub(bidManager, 'addBidResponse'); - sandbox.stub(adLoader, 'loadScript'); - yieldbotLibStub = sandbox.stub(window.yieldbot); - yieldbotLibStub.getSlotCriteria.restore(); + const adapter = new YieldbotAdapter(); + adapter.callBids(bidderRequest); + mockYieldbotBidRequest(); +} - bidManagerStub = sandbox.stub(bidManager, 'addBidResponse'); +function restoreTest() { + sandbox.restore(); + restoreYieldbotMockLib(); +} - const adapter = new YieldbotAdapter(); - adapter.callBids(bidderRequest); - mockYieldbotInitBidRequest(); +describe('Yieldbot adapter tests', function() { + describe('callBids', function() { + beforeEach(function () { + setupTest(); }); afterEach(function() { - sandbox.restore(); - restoreYieldbotMockLib(); + restoreTest(); }); it('should request the yieldbot library', function() { @@ -118,6 +122,23 @@ describe('Yieldbot adapter tests', function() { sinon.assert.calledWith(yieldbotLibStub.defineSlot, 'leaderboard', {sizes: [[728, 90], [970, 90]]}); }); + it('should not use inherited Object properties', function() { + restoreTest(); + + let oProto = Object.prototype; + oProto.superProp = [300, 250]; + + expect(Object.prototype.superProp).to.be.an('array'); + setupTest(); + + sinon.assert.neverCalledWith(yieldbotLibStub.defineSlot, 'superProp', {sizes: [300, 250]}); + sinon.assert.calledWith(yieldbotLibStub.defineSlot, 'medrec', {sizes: [[300, 250], [300, 600]]}); + sinon.assert.calledWith(yieldbotLibStub.defineSlot, 'leaderboard', {sizes: [[728, 90], [970, 90]]}); + + delete oProto.superProp; + expect(Object.prototype.superProp).to.be.an('undefined'); + }); + it('should enable yieldbot async mode', function() { sinon.assert.called(yieldbotLibStub.enableAsync); }); @@ -172,48 +193,79 @@ describe('Yieldbot adapter tests', function() { it('should use yieldbot.nextPageview after first callBids', function() { const adapter = new YieldbotAdapter(); adapter.callBids(bidderRequest); - mockYieldbotInitBidRequest(); + mockYieldbotBidRequest(); expect(window.yieldbot._initialized).to.equal(true); adapter.callBids(bidderRequest); - mockYieldbotInitBidRequest(); + mockYieldbotBidRequest(); sinon.assert.calledOnce(yieldbotLibStub.nextPageview); }); - it('should not throw on callBids without bidsRequested', function() { + it('should call yieldbot.nextPageview with slot config of requested bids', function() { + window.pbjs._bidsRequested = window.pbjs._bidsRequested.filter(o => { + return o.bidderCode !== 'yieldbot'; + }); + const adapter = new YieldbotAdapter(); adapter.callBids(bidderRequest); - mockYieldbotInitBidRequest(); + mockYieldbotBidRequest(); expect(window.yieldbot._initialized).to.equal(true); + sinon.assert.calledWith(yieldbotLibStub.defineSlot, 'medrec'); + sinon.assert.calledWith(yieldbotLibStub.defineSlot, 'leaderboard'); window.pbjs._bidsRequested = window.pbjs._bidsRequested.filter(o => { return o.bidderCode !== 'yieldbot'; }); + const refreshBids = bidderRequest.bids.filter((object) => { return object.placementCode === '/4294967296/adunit1'; }); + let refreshRequest = Object.assign({}, bidderRequest); + refreshRequest.bids = refreshBids; + expect(refreshRequest.bids.length).to.equal(1); + + adapter.callBids(refreshRequest); + mockYieldbotBidRequest(); + + const bid = refreshBids[0]; + const expectedSlots = { 'leaderboard': [[728, 90], [970, 90]] }; + + sinon.assert.calledWithExactly(yieldbotLibStub.nextPageview, expectedSlots); + }); + + it('should not throw on callBids without bidsRequested', function() { + const adapter = new YieldbotAdapter(); adapter.callBids(bidderRequest); - mockYieldbotInitBidRequest(); + mockYieldbotBidRequest(); + + expect(window.yieldbot._initialized).to.equal(true); + + window.$$PREBID_GLOBAL$$._bidsRequested = window.$$PREBID_GLOBAL$$._bidsRequested.filter(o => { + return o.bidderCode !== 'yieldbot'; + }); + + adapter.callBids(bidderRequest); + mockYieldbotBidRequest(); sinon.assert.calledOnce(yieldbotLibStub.nextPageview); }); it('should not add empty bidResponse on callBids without bidsRequested', function() { - window.pbjs._bidsRequested = window.pbjs._bidsRequested.filter(o => { + window.$$PREBID_GLOBAL$$._bidsRequested = window.$$PREBID_GLOBAL$$._bidsRequested.filter(o => { return o.bidderCode !== 'yieldbot'; }); const adapter = new YieldbotAdapter(); adapter.callBids(bidderRequest); - mockYieldbotInitBidRequest(); + mockYieldbotBidRequest(); - let bidResponses = window.pbjs._bidsReceived.filter(o => { + let bidResponses = window.$$PREBID_GLOBAL$$._bidsReceived.filter(o => { return o.bidderCode === 'yieldbot'; }); expect(bidResponses.length).to.equal(0); adapter.callBids(bidderRequest); - mockYieldbotInitBidRequest(); + mockYieldbotBidRequest(); sinon.assert.calledOnce(yieldbotLibStub.nextPageview); }); }); diff --git a/test/spec/renderer_spec.js b/test/spec/renderer_spec.js index ba60923ed2a..282c4841ac0 100644 --- a/test/spec/renderer_spec.js +++ b/test/spec/renderer_spec.js @@ -53,4 +53,39 @@ describe('Renderer: A renderer installed on a bid response', () => { testRenderer1.handleVideoEvent({ id: 1, eventName: 'testEvent' }); expect(spyEventHandler.called).to.equal(true); }); + + it('pushes commands to queue if renderer is not loaded', () => { + testRenderer1.push(spyRenderFn); + + expect(testRenderer1.cmd.length).to.equal(1); + + // clear queue for next tests + testRenderer1.cmd = []; + }); + + it('fires commands immediately if the renderer is loaded', () => { + const func = sinon.spy(); + + testRenderer1.loaded = true; + testRenderer1.push(func); + + expect(testRenderer1.cmd.length).to.equal(0); + sinon.assert.calledOnce(func); + }); + + it('processes queue by calling each function in queue', () => { + testRenderer1.loaded = false; + const func1 = sinon.spy(); + const func2 = sinon.spy(); + + testRenderer1.push(func1); + testRenderer1.push(func2); + expect(testRenderer1.cmd.length).to.equal(2); + + testRenderer1.process(); + + sinon.assert.calledOnce(func1); + sinon.assert.calledOnce(func2); + expect(testRenderer1.cmd.length).to.equal(0); + }); }); diff --git a/test/spec/sizeMapping_spec.js b/test/spec/sizeMapping_spec.js index 55b3080f312..53d4196349f 100644 --- a/test/spec/sizeMapping_spec.js +++ b/test/spec/sizeMapping_spec.js @@ -2,83 +2,82 @@ import { expect } from 'chai'; import * as sizeMapping from 'src/sizeMapping'; var validAdUnit = { - 'sizes': [300,250], + 'sizes': [300, 250], 'sizeMapping': [ { 'minWidth': 1024, - 'sizes': [[300,250],[728,90]] + 'sizes': [[300, 250], [728, 90]] }, { 'minWidth': 480, - 'sizes': [120,60] + 'sizes': [120, 60] }, { 'minWidth': 0, - 'sizes': [20,20] + 'sizes': [20, 20] } ] }; var invalidAdUnit = { - 'sizes': [300,250], + 'sizes': [300, 250], 'sizeMapping': {} // wrong type }; var invalidAdUnit2 = { - 'sizes': [300,250], + 'sizes': [300, 250], 'sizeMapping': [{ - foo : 'bar' //bad + foo: 'bar' // bad }] }; let mockWindow = {}; function resetMockWindow() { - mockWindow = { - document: { - body: { - clientWidth: 1024 - }, - documentElement: { - clientWidth: 1024 - } - }, - innerWidth: 1024 - }; + mockWindow = { + document: { + body: { + clientWidth: 1024 + }, + documentElement: { + clientWidth: 1024 + } + }, + innerWidth: 1024 + }; } describe('sizeMapping', function() { - beforeEach(resetMockWindow); it('mapSizes 1029 width', function() { mockWindow.innerWidth = 1029; sizeMapping.setWindow(mockWindow); let sizes = sizeMapping.mapSizes(validAdUnit); - expect(sizes).to.deep.equal([[300,250],[728,90]]); - expect(validAdUnit.sizes).to.deep.equal([300,250]); + expect(sizes).to.deep.equal([[300, 250], [728, 90]]); + expect(validAdUnit.sizes).to.deep.equal([300, 250]); }); it('mapSizes 400 width', function() { mockWindow.innerWidth = 400; sizeMapping.setWindow(mockWindow); let sizes = sizeMapping.mapSizes(validAdUnit); - expect(sizes).to.deep.equal([20,20]); - expect(validAdUnit.sizes).to.deep.equal([300,250]); + expect(sizes).to.deep.equal([20, 20]); + expect(validAdUnit.sizes).to.deep.equal([300, 250]); }); it('mapSizes - invalid adUnit - should return sizes', function() { mockWindow.innerWidth = 1029; sizeMapping.setWindow(mockWindow); let sizes = sizeMapping.mapSizes(invalidAdUnit); - expect(sizes).to.deep.equal([300,250]); - expect(invalidAdUnit.sizes).to.deep.equal([300,250]); + expect(sizes).to.deep.equal([300, 250]); + expect(invalidAdUnit.sizes).to.deep.equal([300, 250]); mockWindow.innerWidth = 400; sizeMapping.setWindow(mockWindow); sizes = sizeMapping.mapSizes(invalidAdUnit); - expect(sizes).to.deep.equal([300,250]); - expect(invalidAdUnit.sizes).to.deep.equal([300,250]); + expect(sizes).to.deep.equal([300, 250]); + expect(invalidAdUnit.sizes).to.deep.equal([300, 250]); }); it('mapSizes - should return desktop (largest) sizes if screen width not detected', function() { @@ -88,21 +87,19 @@ describe('sizeMapping', function() { sizeMapping.setWindow(mockWindow); let sizes = sizeMapping.mapSizes(validAdUnit); expect(sizes).to.deep.equal([[300, 250], [728, 90]]); - expect(validAdUnit.sizes).to.deep.equal([300,250]); + expect(validAdUnit.sizes).to.deep.equal([300, 250]); }); - it('mapSizes - should return sizes if sizemapping improperly defined ', function() { mockWindow.innerWidth = 0; mockWindow.document.body.clientWidth = 0; mockWindow.document.documentElement.clientWidth = 0; sizeMapping.setWindow(mockWindow); let sizes = sizeMapping.mapSizes(invalidAdUnit2); - expect(sizes).to.deep.equal([300,250]); - expect(validAdUnit.sizes).to.deep.equal([300,250]); + expect(sizes).to.deep.equal([300, 250]); + expect(validAdUnit.sizes).to.deep.equal([300, 250]); }); - it('getScreenWidth', function() { mockWindow.innerWidth = 900; mockWindow.document.body.clientWidth = 900; @@ -116,5 +113,4 @@ describe('sizeMapping', function() { mockWindow.document.documentElement.clientWidth = null; expect(sizeMapping.getScreenWidth(mockWindow)).to.equal(0); }); - }); diff --git a/test/spec/unit/adServerManager_spec.js b/test/spec/unit/adServerManager_spec.js new file mode 100644 index 00000000000..72a3b61ce41 --- /dev/null +++ b/test/spec/unit/adServerManager_spec.js @@ -0,0 +1,30 @@ +import { expect } from 'chai'; +import { getGlobal } from 'src/prebidGlobal'; +import { registerVideoSupport } from 'src/adServerManager'; + +const prebid = getGlobal(); + +describe('The ad server manager', () => { + beforeEach(() => { + delete prebid.adServers; + }); + + it('should register video support to the proper place on the API', () => { + function videoSupport() { } + registerVideoSupport('dfp', { buildVideoUrl: videoSupport }); + + expect(prebid).to.have.property('adServers'); + expect(prebid.adServers).to.have.property('dfp'); + expect(prebid.adServers.dfp).to.have.property('buildVideoUrl', videoSupport); + }); + + it('should keep the first function when we try to add a second', () => { + function videoSupport() { } + registerVideoSupport('dfp', { buildVideoUrl: videoSupport }); + registerVideoSupport('dfp', { buildVideoUrl: function noop() { } }); + + expect(prebid).to.have.property('adServers'); + expect(prebid.adServers).to.have.property('dfp'); + expect(prebid.adServers.dfp).to.have.property('buildVideoUrl', videoSupport); + }); +}); diff --git a/test/spec/unit/adapters/analytics/AnalyticsAdapter_spec.js b/test/spec/unit/adapters/analytics/AnalyticsAdapter_spec.js deleted file mode 100644 index 4e6b862742b..00000000000 --- a/test/spec/unit/adapters/analytics/AnalyticsAdapter_spec.js +++ /dev/null @@ -1,180 +0,0 @@ -import { assert } from 'chai'; -import adaptermanager from '../../../../../src/adaptermanager'; -import events from '../../../../../src/events'; -import CONSTANTS from '../../../../../src/constants.json'; - -const BID_REQUESTED = CONSTANTS.EVENTS.BID_REQUESTED; -const BID_RESPONSE = CONSTANTS.EVENTS.BID_RESPONSE; -const BID_WON = CONSTANTS.EVENTS.BID_WON; -const BID_TIMEOUT = CONSTANTS.EVENTS.BID_TIMEOUT; -const AnalyticsAdapter = require('../../../../../src/adapters/analytics/AnalyticsAdapter').default; -const config = { - url: 'http://localhost:9999/src/adapters/analytics/libraries/example.js', - analyticsType: 'library', - global: 'ExampleAnalyticsGlobalObject', - handler: 'on' -}; - -window[config.global] = () => {}; - -describe(` -FEATURE: Analytics Adapters API - SCENARIO: A publisher enables analytics - GIVEN a global object \`window['testGlobal']\` - AND an \`example\` instance of \`AnalyticsAdapter\`\n`, () => { - - describe(`WHEN an event occurs that is to be tracked\n`, () => { - const eventType = BID_REQUESTED; - const args = { some: 'data' }; - const adapter = new AnalyticsAdapter(config); - var spyTestGlobal = sinon.spy(window, config.global); - - adapter.track({ eventType, args }); - - it(`THEN should call \`window.${config.global}\` function\n`, () => { - assert.ok(spyTestGlobal.args[0][1] === eventType, `with expected event type\n`); - assert.deepEqual(spyTestGlobal.args[0][2], args, `with expected event data\n`); - }); - window[config.global].restore(); - }); - - describe(`WHEN an event occurs before tracking library is available\n`, () => { - const eventType = BID_RESPONSE; - const args = { wat: 'wot' }; - const adapter = new AnalyticsAdapter(config); - - window[config.global] = null; - events.emit(BID_RESPONSE, args); - - describe(`AND the adapter is then enabled\n`, () => { - window[config.global] = () => {}; - - var spyTestGlobal = sinon.spy(window, config.global); - - adapter.enableAnalytics(); - - it(`THEN should queue the event first and then track it\n`, () => { - assert.ok(spyTestGlobal.args[0][1] === eventType, `with expected event type\n`); - assert.deepEqual(spyTestGlobal.args[0][2], args, `with expected event data\n`); - }); - - adapter.disableAnalytics(); - window[config.global].restore(); - }); - }); - - describe(`WHEN an event occurs after enable analytics\n`, () => { - - var spyTestGlobal, - adapter; - - beforeEach(() => { - adapter = new AnalyticsAdapter(config); - spyTestGlobal = sinon.spy(window, config.global); - - sinon.stub(events, "getEvents", () => []); // these tests shouldn't be affected by previous tests - }); - - afterEach(() => { - adapter.disableAnalytics(); - window[config.global].restore(); - - events.getEvents.restore(); - }); - - it('SHOULD call global when a bidWon event occurs', () => { - const eventType = BID_WON; - const args = { more: 'info' }; - - adapter.enableAnalytics(); - events.emit(eventType, args); - - assert.ok(spyTestGlobal.args[0][1] === eventType, `with expected event type\n`); - assert.deepEqual(spyTestGlobal.args[0][2], args, `with expected event data\n`); - }); - - it('SHOULD call global when a bidRequest event occurs', () => { - const eventType = BID_REQUESTED; - const args = { call: 'request' }; - - adapter.enableAnalytics(); - events.emit(eventType, args); - - assert.ok(spyTestGlobal.args[0][1] === eventType, `with expected event type\n`); - assert.deepEqual(spyTestGlobal.args[0][2], args, `with expected event data\n`); - }); - - it('SHOULD call global when a bidResponse event occurs', () => { - const eventType = BID_RESPONSE; - const args = { call: 'response' }; - - adapter.enableAnalytics(); - events.emit(eventType, args); - - assert.ok(spyTestGlobal.args[0][1] === eventType, `with expected event type\n`); - assert.deepEqual(spyTestGlobal.args[0][2], args, `with expected event data\n`); - }); - - it('SHOULD call global when a bidTimeout event occurs', () => { - const eventType = BID_TIMEOUT; - const args = { call: 'timeout' }; - - adapter.enableAnalytics(); - events.emit(eventType, args); - - assert.ok(spyTestGlobal.args[0][1] === eventType, `with expected event type\n`); - assert.deepEqual(spyTestGlobal.args[0][2], args, `with expected event data\n`); - }); - - it('SHOULD NOT call global again when adapter.enableAnalytics is called with previous timeout', () => { - const eventType = BID_TIMEOUT; - const args = { call: 'timeout' }; - - events.emit(eventType, args); - adapter.enableAnalytics(); - events.emit(eventType, args); - - assert(spyTestGlobal.calledOnce === true); - }); - - describe(`AND sampling is enabled\n`, () => { - const eventType = BID_WON; - const args = { more: 'info' }; - - beforeEach(() => { - sinon.stub(Math, "random", () => .5); - }); - - afterEach(() => { - Math.random.restore(); - }); - - it(`THEN should enable analytics when random number is in sample range`, () => { - adapter.enableAnalytics({ - options: { - sampling: .75 - } - }); - events.emit(eventType, args); - - assert(spyTestGlobal.called === true); - }); - - it(`THEN should disable analytics when random number is outside sample range`, () => { - adapter.enableAnalytics({ - options: { - sampling: .25 - } - }); - events.emit(eventType, args); - - assert(spyTestGlobal.called === false); - }); - - }); - - - }); - - - }); diff --git a/test/spec/unit/adapters/analytics/sharethrough_analytics_spec.js b/test/spec/unit/adapters/analytics/sharethrough_analytics_spec.js deleted file mode 100644 index 81a46205d88..00000000000 --- a/test/spec/unit/adapters/analytics/sharethrough_analytics_spec.js +++ /dev/null @@ -1,99 +0,0 @@ -import sharethroughAnalytics from 'src/adapters/analytics/sharethrough_analytics'; -import { expect } from 'chai'; - -describe('sharethrough analytics adapter', () => { - let sandbox; - - beforeEach(() =>{ - sandbox = sinon.sandbox.create(); - }); - - afterEach(() => { - sandbox.restore(); - }); - - describe('track', () => { - - describe('when event type is bidRequested', () => { - - beforeEach(() => { - let eventType = 'bidRequested'; - let args = {"bidderCode" : "sharethrough", "bids":{"0" : {"placementCode" : "fake placement Code"}}}; - sharethroughAnalytics.track({eventType, args}) - }); - - it('placementCodeSet contains a value', () => { - expect(sharethroughAnalytics.placementCodeSet["fake placement Code"] == undefined).to.equal(false) - }); - }); - - }); - - describe('bid won handler', () => { - - let fireLoseBeaconStub; - - beforeEach(() => { - fireLoseBeaconStub = sandbox.stub(sharethroughAnalytics, 'fireLoseBeacon'); - }); - - describe('when bidderCode is not sharethrough and sharethrough is in bid', () => { - beforeEach(() => { - sharethroughAnalytics.placementCodeSet["div-gpt-ad-1460505748561-0"] = {"adserverRequestId" : "0eca470d-fcac-48e6-845a-c86483ccaa0c"} - var args = { - "bidderCode": "someoneelse", - "width": 600, - "height": 300, - "statusMessage": "Bid available", - "adId": "23fbe93a90c924", - "cpm": 3.984986853301525, - "adserverRequestId": "0eca470d-fcac-48e6-845a-c86483ccaa0c", - "winId": "1c404469-f7bb-4e50-b6f6-a8eaf0808999", - "pkey": "xKcxTTHyndFyVx7T8GKSzxPE", - "ad": "
", - "requestId": "dd2420bd-cdc2-4c66-8479-f3499ece73da", - "responseTimestamp": 1473983655565, - "requestTimestamp": 1473983655458, - "bidder": "sharethrough", - "adUnitCode": "div-gpt-ad-1460505748561-0", - "timeToRespond": 107, - "pbLg": "3.50", - "pbMg": "3.90", - "pbHg": "3.98", - "pbAg": "3.95", - "pbDg": "3.95", - "size": "600x300", - "adserverTargeting": { - "hb_bidder": "sharethrough", - "hb_adid": "23fbe93a90c924", - "hb_pb": "3.90", - "hb_size": "600x300" - } - }; - - sharethroughAnalytics.bidWon(args); - - }); - - it('should fire lose beacon', () => { - sinon.assert.calledOnce(fireLoseBeaconStub); - }); - - }); - - }); - - describe('lose beacon is fired', () => { - - beforeEach(() => { - sandbox.stub(sharethroughAnalytics, 'fireBeacon'); - sharethroughAnalytics.fireLoseBeacon('someoneelse', 10.0, 'arid', 'losebeacontype'); - }); - - it('should call correct url', () => { - let winUrl = sharethroughAnalytics.fireBeacon.firstCall.args[0]; - expect(winUrl).to.contain(sharethroughAnalytics.STR_BEACON_HOST + 'winnerBidderCode=someoneelse&winnerCpm=10&arid=arid&type=losebeacontype&hbVersion=%24prebid.version%24&strVersion=0.1.0&hbSource=prebid&'); - }); - }); - -}); \ No newline at end of file diff --git a/test/spec/unit/bidmanager_spec.js b/test/spec/unit/bidmanager_spec.js new file mode 100644 index 00000000000..f01961fd9ba --- /dev/null +++ b/test/spec/unit/bidmanager_spec.js @@ -0,0 +1,213 @@ +import { expect } from 'chai'; +import constants from 'src/constants'; +import events from 'src/events'; + +import * as bidManager from 'src/bidmanager'; +import useVideoCacheStubs from 'test/mocks/videoCacheStub'; +import adUnit from 'test/fixtures/video/adUnit'; +import bidRequest from 'test/fixtures/video/bidRequest'; +import bidResponse from 'test/fixtures/video/bidResponse'; + +function adjustCpm(cpm) { + return cpm + 1; +} + +describe('The Bid Manager', () => { + before(() => { + $$PREBID_GLOBAL$$.cbTimeout = 5000; + $$PREBID_GLOBAL$$.timeoutBuffer = 50; + }); + + describe('addBidResponse() function,', () => { + /** + * Add the bidResponse fixture as a bid into the auction, and run some assertions + * to verify: + * + * 1. Whether or not that bid got added. + * 2. Whether or not the "end of auction" callbacks got called. + */ + function testAddVideoBid(expectBidAdded, expectCallbackCalled, videoCacheStubProvider) { + return function() { + const mockResponse = Object.assign({}, bidResponse); + const callback = sinon.spy(); + bidManager.addOneTimeCallback(callback); + + mockResponse.getSize = function() { + return `${this.height}x${this.width}`; + }; + bidManager.addBidResponse(adUnit.code, mockResponse); + + const expectedBidsReceived = expectBidAdded ? 1 : 0; + expect($$PREBID_GLOBAL$$._bidsReceived.length).to.equal(expectedBidsReceived); + + const storeStub = videoCacheStubProvider().store; + expect(storeStub.calledOnce).to.equal(true); + expect(storeStub.getCall(0).args[0][0]).to.equal(mockResponse); + + if (expectedBidsReceived === 1) { + const bid = $$PREBID_GLOBAL$$._bidsReceived[0]; + + // Ensures that the BidAdjustment listeners execute before the bid goes into the auction. + expect(bid.cpm).to.equal(adjustCpm(0.1)); + + expect(bid.vastUrl).to.equal('www.myVastUrl.com'); + expect(bid.videoCacheKey).to.equal('FAKE_UUID'); + } + if (expectCallbackCalled) { + expect(callback.calledOnce).to.equal(true); + } else { + expect(callback.called).to.equal(false); + } + }; + } + + /** + * Initialize the global state so that the auction-space looks like we want it to. + * + * @param {Array} adUnits The array of ad units which should appear in this auction. + * @param {function} bidRequestTweaker A function which accepts a basic bidRequest, and + * transforms it to prepare it for auction. + */ + function prepAuction(adUnits, bidRequestTweaker) { + function bidAdjuster(bid) { + if (bid.hasOwnProperty('cpm')) { + bid.hadCpmDuringBidAdjustment = true; + } + if (bid.hasOwnProperty('adUnitCode')) { + bid.hadAdUnitCodeDuringBidAdjustment = true; + } + if (bid.hasOwnProperty('timeToRespond')) { + bid.hadTimeToRespondDuringBidAdjustment = true; + } + if (bid.hasOwnProperty('requestTimestamp')) { + bid.hadRequestTimestampDuringBidAdjustment = true; + } + if (bid.hasOwnProperty('responseTimestamp')) { + bid.hadResponseTimestampDuringBidAdjustment = true; + } + bid.cpm = adjustCpm(bid.cpm); + } + beforeEach(() => { + let thisBidRequest = bidRequest; + if (bidRequestTweaker) { + thisBidRequest = JSON.parse(JSON.stringify(bidRequest)); + bidRequestTweaker(thisBidRequest); + } + + events.on(constants.EVENTS.BID_ADJUSTMENT, bidAdjuster); + + $$PREBID_GLOBAL$$.adUnits = adUnits; + $$PREBID_GLOBAL$$._bidsRequested = [thisBidRequest]; + $$PREBID_GLOBAL$$._bidsReceived = []; + $$PREBID_GLOBAL$$._adUnitCodes = $$PREBID_GLOBAL$$.adUnits.map(unit => unit.code); + }); + + afterEach(() => { + events.off(constants.EVENTS.BID_ADJUSTMENT, bidAdjuster); + }); + } + + function auctionStart(timedOut) { + return timedOut + ? new Date().getTime() - $$PREBID_GLOBAL$$.cbTimeout - $$PREBID_GLOBAL$$.timeoutBuffer - 1 + : new Date().getTime(); + } + + describe('when the cache is functioning properly', () => { + let stubProvider = useVideoCacheStubs({ + store: [{ uuid: 'FAKE_UUID' }], + }); + + describe('when more bids are expected after this one', () => { + // Set up the global state so that we expect two bids, and the auction started just now + // (so as to reduce the chance of timeout. This assumes that the unit test runs run in < 5000 ms). + prepAuction( + [adUnit, Object.assign({}, adUnit, { code: 'video2' })], + (bidRequest) => { + const tweakedBidRequestBid = Object.assign({}, bidRequest.bids[0], { placementCode: 'video2' }); + bidRequest.bids.push(tweakedBidRequestBid); + bidRequest.start = auctionStart(false); + }); + + it("should add video bids, but shouldn't call the end-of-auction callbacks yet", + testAddVideoBid(true, false, stubProvider)); + }); + + describe('when this is the last bid expected in the auction', () => { + // Set up the global state so that we expect only one bid, and the auction started just now + // (so as to reduce the chance of timeout. This assumes that the unit test runs run in < 5000 ms). + prepAuction([adUnit], (bidRequest) => bidRequest.start = auctionStart(false)); + + it("shouldn't add invalid bids", () => { + bidManager.addBidResponse('', { }); + bidManager.addBidResponse('testCode', { mediaType: 'video' }); + bidManager.addBidResponse('testCode', { mediaType: 'native' }); + expect($$PREBID_GLOBAL$$._bidsReceived.length).to.equal(0); + }); + + it('should add valid video bids and then execute the callbacks signaling the end of the auction', + testAddVideoBid(true, true, stubProvider)); + + it('should gracefully do nothing when adUnitCode is undefined', () => { + bidManager.addBidResponse(undefined, {}); + expect($$PREBID_GLOBAL$$._bidsReceived.length).to.equal(0); + }); + + it('should gracefully do nothing when bid is undefined', () => { + bidManager.addBidResponse('mock/code'); + expect($$PREBID_GLOBAL$$._bidsReceived.length).to.equal(0); + }); + + it('should attach properties for analytics *before* the BID_ADJUSTMENT event listeners are called', () => { + const copy = Object.assign({}, bidResponse); + copy.getSize = function() { + return `${this.height}x${this.width}`; + }; + delete copy.cpm; + bidManager.addBidResponse('mock/code', copy); + expect(copy).to.have.property('hadCpmDuringBidAdjustment', true); + expect(copy).to.have.property('hadAdUnitCodeDuringBidAdjustment', true); + expect(copy).to.have.property('hadTimeToRespondDuringBidAdjustment', true); + expect(copy).to.have.property('hadRequestTimestampDuringBidAdjustment', true); + expect(copy).to.have.property('hadResponseTimestampDuringBidAdjustment', true); + }); + }); + + describe('when the auction has timed out', () => { + // Set up the global state to expect two bids, and mock an auction which happened long enough + // in the past that it will *seem* like this bid is arriving after the timeouts. + prepAuction( + [adUnit, Object.assign({}, adUnit, { code: 'video2' })], + (bidRequest) => { + const tweakedBidRequestBid = Object.assign({}, bidRequest.bids[0], { placementCode: 'video2' }); + bidRequest.bids.push(tweakedBidRequestBid); + bidRequest.start = auctionStart(true); + }); + + // Because of the preconditions, this makes sure that the end-of-auction callbacks get called when + // the auction hits the timeout. + it('should add the bid, but also execute the callbacks signaling the end of the auction', + testAddVideoBid(true, true, stubProvider)); + }); + }); + + describe('when the cache is failing for some reason,', () => { + let stubProvider = useVideoCacheStubs({ + store: new Error('Unable to save to the cache'), + }); + + // describe('when the auction still has time left', () => { + // prepAuction([adUnit], (bidRequest) => bidRequest.start = auctionStart(false)); + // + // it("shouldn't add the bid to the auction, and shouldn't execute the end-of-auction callbacks", + // testAddVideoBid(false, false, stubProvider)); + // }); + + describe('when the auction has timed out', () => { + prepAuction([adUnit], (bidRequest) => bidRequest.start = auctionStart(true)); + it("shouldn't add the bid to the auction, but should execute the end-of-auction callbacks", + testAddVideoBid(false, true, stubProvider)); + }) + }); + }); +}); diff --git a/test/spec/unit/pbjs_api_spec.js b/test/spec/unit/pbjs_api_spec.js index bae3bc89ea3..3bae15b2898 100644 --- a/test/spec/unit/pbjs_api_spec.js +++ b/test/spec/unit/pbjs_api_spec.js @@ -23,6 +23,10 @@ var events = require('src/events'); var adserver = require('src/adserver'); var CONSTANTS = require('src/constants.json'); +// These bid adapters are required to be loaded for the following tests to work +require('modules/appnexusAstBidAdapter'); +require('modules/adequantBidAdapter'); + var config = require('test/fixtures/config.json'); $$PREBID_GLOBAL$$ = $$PREBID_GLOBAL$$ || {}; @@ -112,37 +116,36 @@ window.googletag = { var createTagAST = function() { var tags = {}; tags[config.adUnitCodes[0]] = { - keywords : {} + keywords: {} }; return tags; }; window.apntag = { keywords: [], - tags : createTagAST(), + tags: createTagAST(), setKeywords: function(key, params) { var self = this; - if(!self.tags.hasOwnProperty(key)) { + if (!self.tags.hasOwnProperty(key)) { return; } self.tags[key].keywords = this.tags[key].keywords || {}; - utils._each(params,function(param,id){ - if (!self.tags[key].keywords.hasOwnProperty(id)) - self.tags[key].keywords[id] = param; - else if (!utils.isArray(self.tags[key].keywords[id])) - self.tags[key].keywords[id] = [self.tags[key].keywords[id]].concat(param); - else - self.tags[key].keywords[id] = self.tags[key].keywords[id].concat(param); + utils._each(params, function(param, id) { + if (!self.tags[key].keywords.hasOwnProperty(id)) { self.tags[key].keywords[id] = param; } else if (!utils.isArray(self.tags[key].keywords[id])) { self.tags[key].keywords[id] = [self.tags[key].keywords[id]].concat(param); } else { self.tags[key].keywords[id] = self.tags[key].keywords[id].concat(param); } }); } }; describe('Unit: Prebid Module', function () { - after(function(){ + after(function() { $$PREBID_GLOBAL$$.adUnits = []; }) describe('getAdserverTargetingForAdUnitCodeStr', function () { + beforeEach(() => { + resetAuction(); + }); + it('should return targeting info as a string', function () { const adUnitCode = config.adUnitCodes[0]; $$PREBID_GLOBAL$$.enableSendAllBids(); @@ -172,7 +175,6 @@ describe('Unit: Prebid Module', function () { }); describe('getAdServerTargeting', function () { - beforeEach(() => { resetAuction(); }); @@ -217,7 +219,6 @@ describe('Unit: Prebid Module', function () { }); it("should include a losing bid's custom ad targeting key when the bid has `alwaysUseBid` set to `true`", () => { - // Let's make sure we're getting the expected losing bid. assert.equal($$PREBID_GLOBAL$$._bidsReceived[0]['bidderCode'], 'triplelift'); assert.equal($$PREBID_GLOBAL$$._bidsReceived[0]['cpm'], 0.112256); @@ -257,32 +258,31 @@ describe('Unit: Prebid Module', function () { assert.deepEqual(targeting, expected); }); - it("should not overwrite winning bids custom keys targeting key when the bid has `alwaysUseBid` set to `true`", () => { - - //mimic a bidderSetting.standard key here for each bid and alwaysUseBid true for every bid + it('should not overwrite winning bids custom keys targeting key when the bid has `alwaysUseBid` set to `true`', () => { + // mimic a bidderSetting.standard key here for each bid and alwaysUseBid true for every bid $$PREBID_GLOBAL$$._bidsReceived.forEach(bid => { bid.adserverTargeting.custom_ad_id = bid.adId; bid.alwaysUseBid = true; }); $$PREBID_GLOBAL$$.bidderSettings = { - "standard": { + 'standard': { adserverTargeting: [{ - key: "hb_bidder", + key: 'hb_bidder', val: function(bidResponse) { return bidResponse.bidderCode; } }, { - key: "custom_ad_id", + key: 'custom_ad_id', val: function(bidResponse) { return bidResponse.adId; } }, { - key: "hb_pb", + key: 'hb_pb', val: function(bidResponse) { return bidResponse.pbMg; } }, { - key: "foobar", + key: 'foobar', val: function(bidResponse) { return bidResponse.size; } @@ -307,17 +307,15 @@ describe('Unit: Prebid Module', function () { hb_pb: '10.00', hb_adid: '24bd938435ec3fc', hb_bidder: 'appnexus', - custom_ad_id:'24bd938435ec3fc' + custom_ad_id: '24bd938435ec3fc' } }; assert.deepEqual(targeting, expected); $$PREBID_GLOBAL$$.bidderSettings = {}; - }); - it("should not send standard targeting keys when the bid has `sendStandardTargeting` set to `false`", () => { - + it('should not send standard targeting keys when the bid has `sendStandardTargeting` set to `false`', () => { $$PREBID_GLOBAL$$._bidsReceived.forEach(bid => { bid.adserverTargeting.custom_ad_id = bid.adId; bid.sendStandardTargeting = false; @@ -332,22 +330,19 @@ describe('Unit: Prebid Module', function () { }, '/19968336/header-bid-tag1': { foobar: '728x90', - custom_ad_id:'24bd938435ec3fc' + custom_ad_id: '24bd938435ec3fc' } }; assert.deepEqual(targeting, expected); $$PREBID_GLOBAL$$.bidderSettings = {}; - }); - }); describe('getBidResponses', function () { - var result = $$PREBID_GLOBAL$$.getBidResponses(); - var compare = getBidResponsesFromAPI(); - it('should return expected bid responses when not passed an adunitCode', function () { + var result = $$PREBID_GLOBAL$$.getBidResponses(); + var compare = getBidResponsesFromAPI(); assert.deepEqual(result, compare, 'expected bid responses are returned'); }); @@ -383,7 +378,7 @@ describe('Unit: Prebid Module', function () { it('should set googletag targeting keys after calling setTargetingForGPTAsync function', function () { var slots = createSlotArrayScenario2(); window.googletag.pubads().setSlots(slots); - $$PREBID_GLOBAL$$.setTargetingForGPTAsync(config.adUnitCodes); + $$PREBID_GLOBAL$$.setTargetingForGPTAsync(); var targeting = []; slots[1].getTargeting().map(function (value) { @@ -396,12 +391,22 @@ describe('Unit: Prebid Module', function () { assert.deepEqual(slots[1].spySetTargeting.args, targeting, 'google tag targeting options not matching'); }); - it('should set targeting when passed an array of ad unit codes', function () { + it('should set targeting when passed a string ad unit code with enableSendAllBids', function () { + var slots = createSlotArray(); + window.googletag.pubads().setSlots(slots); + $$PREBID_GLOBAL$$.enableSendAllBids(); + + $$PREBID_GLOBAL$$.setTargetingForGPTAsync('/19968336/header-bid-tag-0'); + expect(slots[0].spySetTargeting.args).to.deep.contain.members([['hb_bidder', 'appnexus'], ['hb_adid_appnexus', '233bcbee889d46d'], ['hb_pb_appnexus', '10.00']]); + }); + + it('should set targeting when passed an array of ad unit codes with enableSendAllBids', function () { var slots = createSlotArray(); window.googletag.pubads().setSlots(slots); + $$PREBID_GLOBAL$$.enableSendAllBids(); - $$PREBID_GLOBAL$$.setTargetingForGPTAsync(config.adUnitCodes); - expect(slots[0].spySetTargeting.args).to.deep.contain.members([['hb_bidder', 'appnexus']]); + $$PREBID_GLOBAL$$.setTargetingForGPTAsync(['/19968336/header-bid-tag-0']); + expect(slots[0].spySetTargeting.args).to.deep.contain.members([['hb_bidder', 'appnexus'], ['hb_adid_appnexus', '233bcbee889d46d'], ['hb_pb_appnexus', '10.00']]); }); it('should set targeting from googletag data', function () { @@ -427,7 +432,6 @@ describe('Unit: Prebid Module', function () { }); it('should set targeting for bids with `alwaysUseBid=true`', function () { - // Make sure we're getting the expected losing bid. assert.equal($$PREBID_GLOBAL$$._bidsReceived[0]['bidderCode'], 'triplelift'); assert.equal($$PREBID_GLOBAL$$._bidsReceived[0]['cpm'], 0.112256); @@ -441,7 +445,7 @@ describe('Unit: Prebid Module', function () { var slots = createSlotArray(); window.googletag.pubads().setSlots(slots); - $$PREBID_GLOBAL$$.setTargetingForGPTAsync(config.adUnitCodes); + $$PREBID_GLOBAL$$.setTargetingForGPTAsync(); var expected = [ [ @@ -497,7 +501,7 @@ describe('Unit: Prebid Module', function () { $$PREBID_GLOBAL$$.setTargetingForGPTAsync(config.adUnitCodes); sinon.assert.calledOnce(callback); - }) + }); }); describe('allBidsAvailable', function () { @@ -513,6 +517,7 @@ describe('Unit: Prebid Module', function () { describe('renderAd', function () { var bidId = 1; var doc = {}; + var elStub = {}; var adResponse = {}; var spyLogError = null; var spyLogMessage = null; @@ -527,8 +532,14 @@ describe('Unit: Prebid Module', function () { width: 0, height: 0 } - } + }, + getElementsByTagName: sinon.stub() + }; + + elStub = { + insertBefore: sinon.stub() }; + doc.getElementsByTagName.returns([elStub]); adResponse = { adId: bidId, @@ -541,7 +552,7 @@ describe('Unit: Prebid Module', function () { spyLogMessage = sinon.spy(utils, 'logMessage'); inIframe = true; - sinon.stub(utils, "inIframe", () => inIframe); + sinon.stub(utils, 'inIframe', () => inIframe); }); afterEach(function () { @@ -574,8 +585,7 @@ describe('Unit: Prebid Module', function () { it('should place the url inside an iframe on the doc', function () { adResponse.adUrl = 'http://server.example.com/ad/ad.js'; $$PREBID_GLOBAL$$.renderAd(doc, bidId); - var iframe = ''; - assert.ok(doc.write.calledWith(iframe), 'url was written to iframe in doc'); + assert.ok(elStub.insertBefore.called, 'url was written to iframe in doc'); }); it('should log an error when no ad or url', function () { @@ -623,7 +633,6 @@ describe('Unit: Prebid Module', function () { }); describe('requestBids', () => { - var adUnitsBackup; beforeEach(() => { @@ -749,7 +758,7 @@ describe('Unit: Prebid Module', function () { var requestObj = { bidsBackHandler: function bidsBackHandlerCallback() { - var test = undefined; + var test; return test.test; } }; @@ -757,7 +766,6 @@ describe('Unit: Prebid Module', function () { expect(() => { $$PREBID_GLOBAL$$.requestBids(requestObj); }).not.to.throw(); - }); it('should call callBids function on adaptermanager', () => { @@ -807,6 +815,71 @@ describe('Unit: Prebid Module', function () { adaptermanager.videoAdapters = videoAdaptersBackup; }); + it('should only request native bidders on native adunits', () => { + sinon.spy(adaptermanager, 'callBids'); + // appnexusAst is a native bidder, appnexus is not + const adUnits = [{ + code: 'adUnit-code', + mediaType: 'native', + bids: [ + {bidder: 'appnexus', params: {placementId: 'id'}}, + {bidder: 'appnexusAst', params: {placementId: 'id'}} + ] + }]; + + $$PREBID_GLOBAL$$.requestBids({adUnits}); + sinon.assert.calledOnce(adaptermanager.callBids); + + const spyArgs = adaptermanager.callBids.getCall(0); + const biddersCalled = spyArgs.args[0].adUnits[0].bids; + expect(biddersCalled.length).to.equal(1); + + adaptermanager.callBids.restore(); + }); + + it('should callBids if a native adUnit has all native bidders', () => { + sinon.spy(adaptermanager, 'callBids'); + // TODO: appnexusAst is currently hardcoded in native.js, update this text when fixed + const adUnits = [{ + code: 'adUnit-code', + mediaType: 'native', + bids: [ + {bidder: 'appnexusAst', params: {placementId: 'id'}} + ] + }]; + + $$PREBID_GLOBAL$$.requestBids({adUnits}); + sinon.assert.calledOnce(adaptermanager.callBids); + + adaptermanager.callBids.restore(); + }); + + it('splits native type to individual native assets', () => { + $$PREBID_GLOBAL$$._bidsRequested = []; + + const adUnits = [{ + code: 'adUnit-code', + nativeParams: {type: 'image'}, + bids: [ + {bidder: 'appnexusAst', params: {placementId: 'id'}} + ] + }]; + + $$PREBID_GLOBAL$$.requestBids({adUnits}); + + const nativeRequest = $$PREBID_GLOBAL$$._bidsRequested[0].bids[0].nativeParams; + expect(nativeRequest).to.deep.equal({ + image: {required: true}, + title: {required: true}, + sponsoredBy: {required: true}, + clickUrl: {required: true}, + body: {required: false}, + icon: {required: false}, + }); + + resetAuction(); + }); + it('should queue bid requests when a previous bid request is in process', () => { var spyCallBids = sinon.spy(adaptermanager, 'callBids'); var clock = sinon.useFakeTimers(); @@ -842,7 +915,7 @@ describe('Unit: Prebid Module', function () { assert.deepEqual($$PREBID_GLOBAL$$._bidsReceived .filter(bid => requestObj2.adUnitCodes.includes(bid.adUnitCode)).length, 7, 'Placements' + ' for previous request have not been cleared of bids'); - assert.deepEqual($$PREBID_GLOBAL$$._adUnitCodes, ["/19968336/header-bid-tag1"], '_adUnitCodes is' + + assert.deepEqual($$PREBID_GLOBAL$$._adUnitCodes, ['/19968336/header-bid-tag1'], '_adUnitCodes is' + ' for first request'); assert.ok($$PREBID_GLOBAL$$._bidsReceived.length > 0, '_bidsReceived contains bids'); assert.deepEqual($$PREBID_GLOBAL$$.getBidResponses(), {}, 'yet getBidResponses returns' + @@ -855,135 +928,135 @@ describe('Unit: Prebid Module', function () { $$PREBID_GLOBAL$$._bidsReceived = getBidResponses(); assert.ok(spyCallBids.calledTwice, 'The second queued request should callBids when the' + ' first request has completed'); - assert.deepEqual($$PREBID_GLOBAL$$._adUnitCodes, ["/19968336/header-bid-tag-0"], '_adUnitCodes is' + + assert.deepEqual($$PREBID_GLOBAL$$._adUnitCodes, ['/19968336/header-bid-tag-0'], '_adUnitCodes is' + 'now for second request'); assert.deepEqual($$PREBID_GLOBAL$$.getBidResponses(), { - "/19968336/header-bid-tag-0": { - "bids": [ - { - "bidderCode": "brightcom", - "width": 300, - "height": 250, - "statusMessage": "Bid available", - "adId": "26e0795ab963896", - "cpm": 0.17, - "ad": "", - "responseTimestamp": 1462919239420, - "requestTimestamp": 1462919238937, - "bidder": "brightcom", - "adUnitCode": "/19968336/header-bid-tag-0", - "timeToRespond": 483, - "pbLg": "0.00", - "pbMg": "0.10", - "pbHg": "0.17", - "pbAg": "0.15", - "size": "300x250", - "requestId": 654321, - "adserverTargeting": { - "hb_bidder": "brightcom", - "hb_adid": "26e0795ab963896", - "hb_pb": "10.00", - "hb_size": "300x250", - "foobar": "300x250" - } - }, - { - "bidderCode": "brealtime", - "width": 300, - "height": 250, - "statusMessage": "Bid available", - "adId": "275bd666f5a5a5d", - "creative_id": 29681110, - "cpm": 0.5, - "adUrl": "http://lax1-ib.adnxs.com/ab?e=wqT_3QLzBKhzAgAAAwDWAAUBCMjAybkFEIPr4YfMvKLoQBjL84KE1tzG-kkgASotCQAAAQII4D8RAQcQAADgPxkJCQjwPyEJCQjgPykRCaAwuvekAji-B0C-B0gCUNbLkw5YweAnYABokUB4mo8EgAEBigEDVVNEkgUG8FKYAawCoAH6AagBAbABALgBAcABA8gBANABANgBAOABAPABAIoCOnVmKCdhJywgNDk0NDcyLCAxNDYyOTE5MjQwKTt1ZigncicsIDI5NjgxMTEwLDIeAPBvkgLNASFsU2NQWlFpNjBJY0VFTmJMa3c0WUFDREI0Q2N3QURnQVFBUkl2Z2RRdXZla0FsZ0FZSk1IYUFCdzNBMTRDb0FCcGh5SUFRcVFBUUdZQVFHZ0FRR29BUU93QVFDNUFRQUFBQUFBQU9BX3dRRQkMSEFEZ1A4a0JHZmNvazFBejFUX1oVKCRQQV80QUVBOVFFBSw8bUFLS2dOU0NEYUFDQUxVQwUVBEwwCQh0T0FDQU9nQ0FQZ0NBSUFEQVEuLpoCJSFDUWxfYXdpMtAA8KZ3ZUFuSUFRb2lvRFVnZzAu2ALoB-ACx9MB6gIfaHR0cDovL3ByZWJpZC5vcmc6OTk5OS9ncHQuaHRtbIADAIgDAZADAJgDBaADAaoDALADALgDAMADrALIAwDYAwDgAwDoAwD4AwOABACSBAQvanB0mAQAogQKMTAuMS4xMy4zN6gEi-wJsgQICAAQABgAIAC4BADABADIBADSBAsxMC4wLjg1LjIwOA..&s=975cfe6518f064683541240f0d780d93a5f973da&referrer=http%3A%2F%2Fprebid.org%3A9999%2Fgpt.html", - "responseTimestamp": 1462919239486, - "requestTimestamp": 1462919238941, - "bidder": "brealtime", - "adUnitCode": "/19968336/header-bid-tag-0", - "timeToRespond": 545, - "pbLg": "0.50", - "pbMg": "0.50", - "pbHg": "0.50", - "pbAg": "0.50", - "size": "300x250", - "requestId": 654321, - "adserverTargeting": { - "hb_bidder": "brealtime", - "hb_adid": "275bd666f5a5a5d", - "hb_pb": "10.00", - "hb_size": "300x250", - "foobar": "300x250" - } - }, - { - "bidderCode": "pubmatic", - "width": "300", - "height": "250", - "statusMessage": "Bid available", - "adId": "28f4039c636b6a7", - "adSlot": "39620189@300x250", - "cpm": 5.9396, - "ad": "\r
", - "dealId": "", - "responseTimestamp": 1462919239544, - "requestTimestamp": 1462919238922, - "bidder": "pubmatic", - "adUnitCode": "/19968336/header-bid-tag-0", - "timeToRespond": 622, - "pbLg": "5.00", - "pbMg": "5.90", - "pbHg": "5.93", - "pbAg": "5.90", - "size": "300x250", - "requestId": 654321, - "adserverTargeting": { - "hb_bidder": "pubmatic", - "hb_adid": "28f4039c636b6a7", - "hb_pb": "10.00", - "hb_size": "300x250", - "foobar": "300x250" - } - }, - { - "bidderCode": "rubicon", - "width": 300, - "height": 600, - "statusMessage": "Bid available", - "adId": "29019e2ab586a5a", - "cpm": 2.74, - "ad": "", - "responseTimestamp": 1462919239860, - "requestTimestamp": 1462919238934, - "bidder": "rubicon", - "adUnitCode": "/19968336/header-bid-tag-0", - "timeToRespond": 926, - "pbLg": "2.50", - "pbMg": "2.70", - "pbHg": "2.74", - "pbAg": "2.70", - "size": "300x600", - "requestId": 654321, - "adserverTargeting": { - "hb_bidder": "rubicon", - "hb_adid": "29019e2ab586a5a", - "hb_pb": "10.00", - "hb_size": "300x600", - "foobar": "300x600" + '/19968336/header-bid-tag-0': { + 'bids': [ + { + 'bidderCode': 'brightcom', + 'width': 300, + 'height': 250, + 'statusMessage': 'Bid available', + 'adId': '26e0795ab963896', + 'cpm': 0.17, + 'ad': "", + 'responseTimestamp': 1462919239420, + 'requestTimestamp': 1462919238937, + 'bidder': 'brightcom', + 'adUnitCode': '/19968336/header-bid-tag-0', + 'timeToRespond': 483, + 'pbLg': '0.00', + 'pbMg': '0.10', + 'pbHg': '0.17', + 'pbAg': '0.15', + 'size': '300x250', + 'requestId': 654321, + 'adserverTargeting': { + 'hb_bidder': 'brightcom', + 'hb_adid': '26e0795ab963896', + 'hb_pb': '10.00', + 'hb_size': '300x250', + 'foobar': '300x250' + } + }, + { + 'bidderCode': 'brealtime', + 'width': 300, + 'height': 250, + 'statusMessage': 'Bid available', + 'adId': '275bd666f5a5a5d', + 'creative_id': 29681110, + 'cpm': 0.5, + 'adUrl': 'http://lax1-ib.adnxs.com/ab?e=wqT_3QLzBKhzAgAAAwDWAAUBCMjAybkFEIPr4YfMvKLoQBjL84KE1tzG-kkgASotCQAAAQII4D8RAQcQAADgPxkJCQjwPyEJCQjgPykRCaAwuvekAji-B0C-B0gCUNbLkw5YweAnYABokUB4mo8EgAEBigEDVVNEkgUG8FKYAawCoAH6AagBAbABALgBAcABA8gBANABANgBAOABAPABAIoCOnVmKCdhJywgNDk0NDcyLCAxNDYyOTE5MjQwKTt1ZigncicsIDI5NjgxMTEwLDIeAPBvkgLNASFsU2NQWlFpNjBJY0VFTmJMa3c0WUFDREI0Q2N3QURnQVFBUkl2Z2RRdXZla0FsZ0FZSk1IYUFCdzNBMTRDb0FCcGh5SUFRcVFBUUdZQVFHZ0FRR29BUU93QVFDNUFRQUFBQUFBQU9BX3dRRQkMSEFEZ1A4a0JHZmNvazFBejFUX1oVKCRQQV80QUVBOVFFBSw8bUFLS2dOU0NEYUFDQUxVQwUVBEwwCQh0T0FDQU9nQ0FQZ0NBSUFEQVEuLpoCJSFDUWxfYXdpMtAA8KZ3ZUFuSUFRb2lvRFVnZzAu2ALoB-ACx9MB6gIfaHR0cDovL3ByZWJpZC5vcmc6OTk5OS9ncHQuaHRtbIADAIgDAZADAJgDBaADAaoDALADALgDAMADrALIAwDYAwDgAwDoAwD4AwOABACSBAQvanB0mAQAogQKMTAuMS4xMy4zN6gEi-wJsgQICAAQABgAIAC4BADABADIBADSBAsxMC4wLjg1LjIwOA..&s=975cfe6518f064683541240f0d780d93a5f973da&referrer=http%3A%2F%2Fprebid.org%3A9999%2Fgpt.html', + 'responseTimestamp': 1462919239486, + 'requestTimestamp': 1462919238941, + 'bidder': 'brealtime', + 'adUnitCode': '/19968336/header-bid-tag-0', + 'timeToRespond': 545, + 'pbLg': '0.50', + 'pbMg': '0.50', + 'pbHg': '0.50', + 'pbAg': '0.50', + 'size': '300x250', + 'requestId': 654321, + 'adserverTargeting': { + 'hb_bidder': 'brealtime', + 'hb_adid': '275bd666f5a5a5d', + 'hb_pb': '10.00', + 'hb_size': '300x250', + 'foobar': '300x250' + } + }, + { + 'bidderCode': 'pubmatic', + 'width': '300', + 'height': '250', + 'statusMessage': 'Bid available', + 'adId': '28f4039c636b6a7', + 'adSlot': '39620189@300x250', + 'cpm': 5.9396, + 'ad': "\r
", + 'dealId': '', + 'responseTimestamp': 1462919239544, + 'requestTimestamp': 1462919238922, + 'bidder': 'pubmatic', + 'adUnitCode': '/19968336/header-bid-tag-0', + 'timeToRespond': 622, + 'pbLg': '5.00', + 'pbMg': '5.90', + 'pbHg': '5.93', + 'pbAg': '5.90', + 'size': '300x250', + 'requestId': 654321, + 'adserverTargeting': { + 'hb_bidder': 'pubmatic', + 'hb_adid': '28f4039c636b6a7', + 'hb_pb': '10.00', + 'hb_size': '300x250', + 'foobar': '300x250' + } + }, + { + 'bidderCode': 'rubicon', + 'width': 300, + 'height': 600, + 'statusMessage': 'Bid available', + 'adId': '29019e2ab586a5a', + 'cpm': 2.74, + 'ad': '', + 'responseTimestamp': 1462919239860, + 'requestTimestamp': 1462919238934, + 'bidder': 'rubicon', + 'adUnitCode': '/19968336/header-bid-tag-0', + 'timeToRespond': 926, + 'pbLg': '2.50', + 'pbMg': '2.70', + 'pbHg': '2.74', + 'pbAg': '2.70', + 'size': '300x600', + 'requestId': 654321, + 'adserverTargeting': { + 'hb_bidder': 'rubicon', + 'hb_adid': '29019e2ab586a5a', + 'hb_pb': '10.00', + 'hb_size': '300x600', + 'foobar': '300x600' + } + } + ] } - } - ] - } -}, 'getBidResponses returns info for current bid request'); + }, 'getBidResponses returns info for current bid request'); assert.deepEqual($$PREBID_GLOBAL$$.getAdserverTargeting(), { - "/19968336/header-bid-tag-0": { - "foobar": "300x250", - "hb_size": "300x250", - "hb_pb": "10.00", - "hb_adid": "233bcbee889d46d", - "hb_bidder": "appnexus" - } -}, 'targeting info returned for current placements'); + '/19968336/header-bid-tag-0': { + 'foobar': '300x250', + 'hb_size': '300x250', + 'hb_pb': '10.00', + 'hb_adid': '233bcbee889d46d', + 'hb_bidder': 'appnexus' + } + }, 'targeting info returned for current placements'); resetAuction(); adaptermanager.callBids.restore(); }); @@ -1138,7 +1211,7 @@ describe('Unit: Prebid Module', function () { }); }); - //describe('enableAnalytics', () => { + // describe('enableAnalytics', () => { // let logErrorSpy; // // beforeEach(() => { @@ -1184,7 +1257,7 @@ describe('Unit: Prebid Module', function () { // const returnValue = $$PREBID_GLOBAL$$.enableAnalytics(options); // assert.equal(returnValue, null, 'expected return value'); // }); - //}); + // }); describe('sendTimeoutEvent', () => { it('should emit BID_TIMEOUT for timed out bids', () => { @@ -1255,17 +1328,17 @@ describe('Unit: Prebid Module', function () { const logErrorSpy = sinon.spy(utils, 'logError'); const error = 'Invalid custom price value passed to `setPriceGranularity()`'; const badConfig = { - "buckets" : [{ - "min" : 0, - "max" : 3, - "increment" : 0.01, - }, - { - //missing min prop - "max" : 18, - "increment" : 0.05, - "cap" : true - } + 'buckets': [{ + 'min': 0, + 'max': 3, + 'increment': 0.01, + }, + { + // missing min prop + 'max': 18, + 'increment': 0.05, + 'cap': true + } ] }; @@ -1278,12 +1351,12 @@ describe('Unit: Prebid Module', function () { const setCustomPriceBucket = sinon.spy(bidmanager, 'setCustomPriceBucket'); const setPriceGranularitySpy = sinon.spy(bidmanager, 'setPriceGranularity'); const goodConfig = { - "buckets" : [{ - "min" : 0, - "max" : 3, - "increment" : 0.01, - "cap" : true - } + 'buckets': [{ + 'min': 0, + 'max': 3, + 'increment': 0.01, + 'cap': true + } ] }; @@ -1308,7 +1381,6 @@ describe('Unit: Prebid Module', function () { describe('emit event', () => { it('should call AUCTION_END only once', () => { - resetAuction(); var spyClearAuction = sinon.spy($$PREBID_GLOBAL$$, 'clearAuction'); var clock1 = sinon.useFakeTimers(); @@ -1323,56 +1395,56 @@ describe('Unit: Prebid Module', function () { assert.ok(spyClearAuction.calledOnce, true); $$PREBID_GLOBAL$$._bidsRequested = [{ - "bidderCode": "appnexus", - "requestId": "1863e370099523", - "bidderRequestId": "2946b569352ef2", - "bids": [ + 'bidderCode': 'appnexus', + 'requestId': '1863e370099523', + 'bidderRequestId': '2946b569352ef2', + 'bids': [ { - "bidder": "appnexus", - "params": { - "placementId": "4799418", - "test": "me" + 'bidder': 'appnexus', + 'params': { + 'placementId': '4799418', + 'test': 'me' }, - "placementCode": "/19968336/header-bid-tag1", - "sizes": [[728,90],[970,90]], - "bidId": "392b5a6b05d648", - "bidderRequestId": "2946b569352ef2", - "requestId": "1863e370099523", - "startTime": 1462918897462, - "status": 1 + 'placementCode': '/19968336/header-bid-tag1', + 'sizes': [[728, 90], [970, 90]], + 'bidId': '392b5a6b05d648', + 'bidderRequestId': '2946b569352ef2', + 'requestId': '1863e370099523', + 'startTime': 1462918897462, + 'status': 1 } ], - "start": 1462918897460 + 'start': 1462918897460 }]; $$PREBID_GLOBAL$$._bidsReceived = []; var bid = Object.assign({ - "bidderCode": "appnexus", - "width": 728, - "height": 90, - "statusMessage": "Bid available", - "adId": "24bd938435ec3fc", - "creative_id": 33989846, - "cpm": 0, - "adUrl": "http://lax1-ib.adnxs.com/ab?e=wqT_3QLyBKhyAgAAAwDWAAUBCMjAybkFEOOryfjI7rGNWhjL84KE1tzG-kkgASotCQAAAQII4D8RAQcQAADgPxkJCQjwPyEJCQjgPykRCaAwuvekAji-B0C-B0gCUNbJmhBYweAnYABokUB4mt0CgAEBigEDVVNEkgUG8ECYAdgFoAFaqAEBsAEAuAEBwAEDyAEA0AEA2AEA4AEA8AEAigI6dWYoJ2EnLCA0OTQ0NzIsIDE0NjI5MTkyNDApOwEcLHInLCAzMzk4OTg0NjYeAPBvkgLNASFwU2Y1YUFpNjBJY0VFTmJKbWhBWUFDREI0Q2N3QURnQVFBUkl2Z2RRdXZla0FsZ0FZSk1IYUFCd3lnNTRDb0FCcGh5SUFRcVFBUUdZQVFHZ0FRR29BUU93QVFDNUFRQUFBQUFBQU9BX3dRRQkMSEFEZ1A4a0JJNTJDbGs5VjB6X1oVKCRQQV80QUVBOVFFBSw8bUFLS2dNQ0NENkFDQUxVQwUVBEwwCQh0T0FDQU9nQ0FQZ0NBSUFEQVEuLpoCJSFfZ2lqYXdpMtAA8KZ3ZUFuSUFRb2lvREFnZzgu2ALoB-ACx9MB6gIfaHR0cDovL3ByZWJpZC5vcmc6OTk5OS9ncHQuaHRtbIADAIgDAZADAJgDBaADAaoDALADALgDAMADrALIAwDYAwDgAwDoAwD4AwOABACSBAQvanB0mAQAogQKMTAuMS4xMy4zN6gEi-wJsgQICAAQABgAIAC4BADABADIBADSBAsxMC4wLjgwLjI0MA..&s=1f584d32c2d7ae3ce3662cfac7ca24e710bc7fd0&referrer=http%3A%2F%2Fprebid.org%3A9999%2Fgpt.html", - "responseTimestamp": 1462919239342, - "requestTimestamp": 1462919238919, - "bidder": "appnexus", - "adUnitCode": "/19968336/header-bid-tag1", - "timeToRespond": 423, - "pbLg": "5.00", - "pbMg": "10.00", - "pbHg": "10.00", - "pbAg": "10.00", - "size": "728x90", - "alwaysUseBid": true, - "adserverTargeting": { - "hb_bidder": "appnexus", - "hb_adid": "24bd938435ec3fc", - "hb_pb": "10.00", - "hb_size": "728x90", - "foobar": "728x90" + 'bidderCode': 'appnexus', + 'width': 728, + 'height': 90, + 'statusMessage': 'Bid available', + 'adId': '24bd938435ec3fc', + 'creative_id': 33989846, + 'cpm': 0, + 'adUrl': 'http://lax1-ib.adnxs.com/ab?e=wqT_3QLyBKhyAgAAAwDWAAUBCMjAybkFEOOryfjI7rGNWhjL84KE1tzG-kkgASotCQAAAQII4D8RAQcQAADgPxkJCQjwPyEJCQjgPykRCaAwuvekAji-B0C-B0gCUNbJmhBYweAnYABokUB4mt0CgAEBigEDVVNEkgUG8ECYAdgFoAFaqAEBsAEAuAEBwAEDyAEA0AEA2AEA4AEA8AEAigI6dWYoJ2EnLCA0OTQ0NzIsIDE0NjI5MTkyNDApOwEcLHInLCAzMzk4OTg0NjYeAPBvkgLNASFwU2Y1YUFpNjBJY0VFTmJKbWhBWUFDREI0Q2N3QURnQVFBUkl2Z2RRdXZla0FsZ0FZSk1IYUFCd3lnNTRDb0FCcGh5SUFRcVFBUUdZQVFHZ0FRR29BUU93QVFDNUFRQUFBQUFBQU9BX3dRRQkMSEFEZ1A4a0JJNTJDbGs5VjB6X1oVKCRQQV80QUVBOVFFBSw8bUFLS2dNQ0NENkFDQUxVQwUVBEwwCQh0T0FDQU9nQ0FQZ0NBSUFEQVEuLpoCJSFfZ2lqYXdpMtAA8KZ3ZUFuSUFRb2lvREFnZzgu2ALoB-ACx9MB6gIfaHR0cDovL3ByZWJpZC5vcmc6OTk5OS9ncHQuaHRtbIADAIgDAZADAJgDBaADAaoDALADALgDAMADrALIAwDYAwDgAwDoAwD4AwOABACSBAQvanB0mAQAogQKMTAuMS4xMy4zN6gEi-wJsgQICAAQABgAIAC4BADABADIBADSBAsxMC4wLjgwLjI0MA..&s=1f584d32c2d7ae3ce3662cfac7ca24e710bc7fd0&referrer=http%3A%2F%2Fprebid.org%3A9999%2Fgpt.html', + 'responseTimestamp': 1462919239342, + 'requestTimestamp': 1462919238919, + 'bidder': 'appnexus', + 'adUnitCode': '/19968336/header-bid-tag1', + 'timeToRespond': 423, + 'pbLg': '5.00', + 'pbMg': '10.00', + 'pbHg': '10.00', + 'pbAg': '10.00', + 'size': '728x90', + 'alwaysUseBid': true, + 'adserverTargeting': { + 'hb_bidder': 'appnexus', + 'hb_adid': '24bd938435ec3fc', + 'hb_pb': '10.00', + 'hb_size': '728x90', + 'foobar': '728x90' } }, bidfactory.createBid(2)); @@ -1387,7 +1459,7 @@ describe('Unit: Prebid Module', function () { const adUnitCode = '/19968336/header-bid-tag1'; $$PREBID_GLOBAL$$.addBidResponse(adUnitCode, bid); - assert.equal(spyClearAuction.callCount,1, 'AUCTION_END event emitted more than once'); + assert.equal(spyClearAuction.callCount, 1, 'AUCTION_END event emitted more than once'); clock1.restore(); resetAuction(); @@ -1408,9 +1480,9 @@ describe('Unit: Prebid Module', function () { bids: [{ bidder: 'rubicon', params: { - accountId: "1234", - siteId: "1234", - zoneId: "1234" + accountId: '1234', + siteId: '1234', + zoneId: '1234' } }] }; @@ -1420,12 +1492,10 @@ describe('Unit: Prebid Module', function () { assert.deepEqual($$PREBID_GLOBAL$$.adUnits, adUnits); $$PREBID_GLOBAL$$.removeAdUnit('adUnit1'); assert.deepEqual($$PREBID_GLOBAL$$.adUnits, [adUnit2]); - }); }); describe('getDealTargeting', () => { - beforeEach(() => { resetAuction(); }); @@ -1437,34 +1507,34 @@ describe('Unit: Prebid Module', function () { it('should truncate deal keys', () => { $$PREBID_GLOBAL$$._bidsReceived = [ { - "bidderCode": "appnexusDummyName", - "dealId" : "1234", - "width": 300, - "height": 250, - "statusMessage": "Bid available", - "adId": "233bcbee889d46d", - "creative_id": 29681110, - "cpm": 10, - "adUrl": "http://lax1-ib.adnxs.com/ab?e=wqT_3QL8BKh8AgAAAwDWAAUBCMjAybkFEMLLiJWTu9PsVxjL84KE1tzG-kkgASotCQAAAQII4D8RAQcQAADgPxkJCQjwPyEJCQjgPykRCaAwuvekAji-B0C-B0gCUNbLkw5YweAnYABokUB4190DgAEBigEDVVNEkgUG8FKYAawCoAH6AagBAbABALgBAcABA8gBANABANgBAOABAPABAIoCOnVmKCdhJywgNDk0NDcyLCAxNDYyOTE5MjQwKTt1ZigncicsIDI5NjgxMTEwLDIeAPBskgLZASFmU21rZ0FpNjBJY0VFTmJMa3c0WUFDREI0Q2N3QURnQVFBUkl2Z2RRdXZla0FsZ0FZSk1IYUFCd0EzZ0RnQUVEaUFFRGtBRUJtQUVCb0FFQnFBRURzQUVBdVFFQUFBQUFBQURnUDhFQgkMTEFBNERfSkFRMkxMcEVUMU93XzJRFSggd1AtQUJBUFVCBSxASmdDaW9EVTJnV2dBZ0MxQWcBFgRDOQkIqERBQWdQSUFnUFFBZ1BZQWdQZ0FnRG9BZ0Q0QWdDQUF3RS6aAiUhV1FrbmI63AAcd2VBbklBUW8JXPCVVS7YAugH4ALH0wHqAh9odHRwOi8vcHJlYmlkLm9yZzo5OTk5L2dwdC5odG1sgAMAiAMBkAMAmAMFoAMBqgMAsAMAuAMAwAOsAsgDANgDAOADAOgDAPgDA4AEAJIEBC9qcHSYBACiBAoxMC4xLjEzLjM3qAQAsgQICAAQABgAIAC4BADABADIBADSBAoxMC4wLjg1Ljkx&s=1bf15e8cdc7c0c8c119614c6386ab1496560da39&referrer=http%3A%2F%2Fprebid.org%3A9999%2Fgpt.html", - "responseTimestamp": 1462919239340, - "requestTimestamp": 1462919238919, - "bidder": "appnexus", - "adUnitCode": "/19968336/header-bid-tag-0", - "timeToRespond": 421, - "pbLg": "5.00", - "pbMg": "10.00", - "pbHg": "10.00", - "pbAg": "10.00", - "size": "300x250", - "alwaysUseBid": true, - "requestId": 123456, - "adserverTargeting": { - "hb_bidder": "appnexus", - "hb_adid": "233bcbee889d46d", - "hb_pb": "10.00", - "hb_size": "300x250", - "foobar": "300x250", - "hb_deal_appnexusDummyName": "1234" + 'bidderCode': 'appnexusDummyName', + 'dealId': '1234', + 'width': 300, + 'height': 250, + 'statusMessage': 'Bid available', + 'adId': '233bcbee889d46d', + 'creative_id': 29681110, + 'cpm': 10, + 'adUrl': 'http://lax1-ib.adnxs.com/ab?e=wqT_3QL8BKh8AgAAAwDWAAUBCMjAybkFEMLLiJWTu9PsVxjL84KE1tzG-kkgASotCQAAAQII4D8RAQcQAADgPxkJCQjwPyEJCQjgPykRCaAwuvekAji-B0C-B0gCUNbLkw5YweAnYABokUB4190DgAEBigEDVVNEkgUG8FKYAawCoAH6AagBAbABALgBAcABA8gBANABANgBAOABAPABAIoCOnVmKCdhJywgNDk0NDcyLCAxNDYyOTE5MjQwKTt1ZigncicsIDI5NjgxMTEwLDIeAPBskgLZASFmU21rZ0FpNjBJY0VFTmJMa3c0WUFDREI0Q2N3QURnQVFBUkl2Z2RRdXZla0FsZ0FZSk1IYUFCd0EzZ0RnQUVEaUFFRGtBRUJtQUVCb0FFQnFBRURzQUVBdVFFQUFBQUFBQURnUDhFQgkMTEFBNERfSkFRMkxMcEVUMU93XzJRFSggd1AtQUJBUFVCBSxASmdDaW9EVTJnV2dBZ0MxQWcBFgRDOQkIqERBQWdQSUFnUFFBZ1BZQWdQZ0FnRG9BZ0Q0QWdDQUF3RS6aAiUhV1FrbmI63AAcd2VBbklBUW8JXPCVVS7YAugH4ALH0wHqAh9odHRwOi8vcHJlYmlkLm9yZzo5OTk5L2dwdC5odG1sgAMAiAMBkAMAmAMFoAMBqgMAsAMAuAMAwAOsAsgDANgDAOADAOgDAPgDA4AEAJIEBC9qcHSYBACiBAoxMC4xLjEzLjM3qAQAsgQICAAQABgAIAC4BADABADIBADSBAoxMC4wLjg1Ljkx&s=1bf15e8cdc7c0c8c119614c6386ab1496560da39&referrer=http%3A%2F%2Fprebid.org%3A9999%2Fgpt.html', + 'responseTimestamp': 1462919239340, + 'requestTimestamp': 1462919238919, + 'bidder': 'appnexus', + 'adUnitCode': '/19968336/header-bid-tag-0', + 'timeToRespond': 421, + 'pbLg': '5.00', + 'pbMg': '10.00', + 'pbHg': '10.00', + 'pbAg': '10.00', + 'size': '300x250', + 'alwaysUseBid': true, + 'requestId': 123456, + 'adserverTargeting': { + 'hb_bidder': 'appnexus', + 'hb_adid': '233bcbee889d46d', + 'hb_pb': '10.00', + 'hb_size': '300x250', + 'foobar': '300x250', + 'hb_deal_appnexusDummyName': '1234' } } ]; @@ -1477,68 +1547,67 @@ describe('Unit: Prebid Module', function () { }); describe('video adserverTag', () => { - var adserverTag = 'https://pubads.g.doubleclick.net/gampad/ads?sz=640x480&iu=/19968336/header-bid-tag-0&impl=s&gdfp_req=1&env=vp&output=xml_vast2&unviewed_position_start=1&url=www.test.com'; var options = { - 'adserver': 'dfp', - 'code': '/19968336/header-bid-tag-0' - }; + 'adserver': 'dfp', + 'code': '/19968336/header-bid-tag-0' + }; beforeEach(() => { resetAuction(); $$PREBID_GLOBAL$$._bidsReceived = [ { - "bidderCode": "appnexusAstDummyName", - "width": 0, - "height": 0, - "statusMessage": "Bid returned empty or error response", - "adId": "233bcbee889d46d", - "requestId": 123456, - "responseTimestamp": 1462919238959, - "requestTimestamp": 1462919238910, - "cpm": 0, - "bidder": "appnexus", - "adUnitCode": "/19968336/header-bid-tag-0", - "timeToRespond": 49, - "pbLg": "0.00", - "pbMg": "0.00", - "pbHg": "0.00", - "pbAg": "0.00", - "pbDg": "0.00", - "pbCg": "", - "adserverTargeting": {} + 'bidderCode': 'appnexusAstDummyName', + 'width': 0, + 'height': 0, + 'statusMessage': 'Bid returned empty or error response', + 'adId': '233bcbee889d46d', + 'requestId': 123456, + 'responseTimestamp': 1462919238959, + 'requestTimestamp': 1462919238910, + 'cpm': 0, + 'bidder': 'appnexus', + 'adUnitCode': '/19968336/header-bid-tag-0', + 'timeToRespond': 49, + 'pbLg': '0.00', + 'pbMg': '0.00', + 'pbHg': '0.00', + 'pbAg': '0.00', + 'pbDg': '0.00', + 'pbCg': '', + 'adserverTargeting': {} }, { - "bidderCode": "appnexusAst", - "dealId" : "1234", - "width": 300, - "height": 250, - "statusMessage": "Bid available", - "adId": "233bcbee889d46d", - "creative_id": 29681110, - "cpm": 10, - "vastUrl": "http://www.simplevideoad.com/", - "descriptionUrl": "http://www.simplevideoad.com/", - "responseTimestamp": 1462919239340, - "requestTimestamp": 1462919238919, - "bidder": "appnexus", - "adUnitCode": "/19968336/header-bid-tag-0", - "timeToRespond": 421, - "pbLg": "5.00", - "pbMg": "10.00", - "pbHg": "10.00", - "pbAg": "10.00", - "size": "300x250", - "alwaysUseBid": true, - "requestId": 123456, - "adserverTargeting": { - "hb_bidder": "appnexus", - "hb_adid": "233bcbee889d46d", - "hb_pb": "10.00", - "hb_size": "300x250", - "foobar": "300x250", - "hb_deal_appnexusAst": "1234" + 'bidderCode': 'appnexusAst', + 'dealId': '1234', + 'width': 300, + 'height': 250, + 'statusMessage': 'Bid available', + 'adId': '233bcbee889d46d', + 'creative_id': 29681110, + 'cpm': 10, + 'vastUrl': 'http://www.simplevideoad.com/', + 'descriptionUrl': 'http://www.simplevideoad.com/', + 'responseTimestamp': 1462919239340, + 'requestTimestamp': 1462919238919, + 'bidder': 'appnexus', + 'adUnitCode': '/19968336/header-bid-tag-0', + 'timeToRespond': 421, + 'pbLg': '5.00', + 'pbMg': '10.00', + 'pbHg': '10.00', + 'pbAg': '10.00', + 'size': '300x250', + 'alwaysUseBid': true, + 'requestId': 123456, + 'adserverTargeting': { + 'hb_bidder': 'appnexus', + 'hb_adid': '233bcbee889d46d', + 'hb_pb': '10.00', + 'hb_size': '300x250', + 'foobar': '300x250', + 'hb_deal_appnexusAst': '1234' } } ]; @@ -1551,9 +1620,9 @@ describe('Unit: Prebid Module', function () { it('should log error when adserver is not dfp', () => { var logErrorSpy = sinon.spy(utils, 'logError'); var options = { - 'adserver': 'anyother', - 'code': '/19968336/header-bid-tag-0' - }; + 'adserver': 'anyother', + 'code': '/19968336/header-bid-tag-0' + }; var masterTagUrl = $$PREBID_GLOBAL$$.buildMasterVideoTagFromAdserverTag(adserverTag, options); assert.ok(logErrorSpy.calledOnce, true); utils.logError.restore(); @@ -1654,7 +1723,7 @@ describe('Unit: Prebid Module', function () { var expectedAdserverTargeting = bids[0].adserverTargeting; var newAdserverTargeting = {}; - for(var key in expectedAdserverTargeting) { + for (var key in expectedAdserverTargeting) { var nkey = (key === 'hb_adid') ? key.toUpperCase() : key; newAdserverTargeting[nkey] = expectedAdserverTargeting[key]; } @@ -1672,6 +1741,40 @@ describe('Unit: Prebid Module', function () { }); }); + describe('The monkey-patched queue.push function', function() { + beforeEach(function initializeSpies() { + sinon.spy(utils, 'logError'); + }); + + afterEach(function resetSpies() { + utils.logError.restore(); + }); + + it('should run commands which are pushed into it', function() { + let cmd = sinon.spy(); + $$PREBID_GLOBAL$$.cmd.push(cmd); + assert.isTrue(cmd.called); + }); + + it('should log an error when given non-functions', function() { + $$PREBID_GLOBAL$$.cmd.push(5); + assert.isTrue(utils.logError.calledOnce); + }); + + it('should log an error if the command passed into it fails', function() { + $$PREBID_GLOBAL$$.cmd.push(function() { + throw new Error('Failed function.'); + }); + assert.isTrue(utils.logError.calledOnce); + }); + }); + + describe('The monkey-patched que.push function', function() { + it('should be the same as the cmd.push function', function() { + assert.equal($$PREBID_GLOBAL$$.que.push, $$PREBID_GLOBAL$$.cmd.push); + }); + }); + describe('setS2SConfig', () => { let logErrorSpy; @@ -1685,11 +1788,11 @@ describe('Unit: Prebid Module', function () { it('should log error when accountId is missing', () => { const options = { - enabled : true, - bidders : ['appnexus'], - timeout : 1000, - adapter : 'prebidServer', - endpoint : 'https://prebid.adnxs.com/pbs/v1/auction' + enabled: true, + bidders: ['appnexus'], + timeout: 1000, + adapter: 'prebidServer', + endpoint: 'https://prebid.adnxs.com/pbs/v1/auction' }; $$PREBID_GLOBAL$$.setS2SConfig(options); @@ -1698,16 +1801,15 @@ describe('Unit: Prebid Module', function () { it('should log error when bidders is missing', () => { const options = { - accountId : '1', - enabled : true, - timeout : 1000, - adapter : 's2s', - endpoint : 'https://prebid.adnxs.com/pbs/v1/auction' + accountId: '1', + enabled: true, + timeout: 1000, + adapter: 's2s', + endpoint: 'https://prebid.adnxs.com/pbs/v1/auction' }; $$PREBID_GLOBAL$$.setS2SConfig(options); assert.ok(logErrorSpy.calledOnce, true); }); }); - }); diff --git a/test/spec/url_spec.js b/test/spec/url_spec.js index 55b7de5b04f..2b60549ef63 100644 --- a/test/spec/url_spec.js +++ b/test/spec/url_spec.js @@ -2,9 +2,7 @@ import {format, parse} from '../../src/url'; import { expect } from 'chai'; describe('helpers.url', () => { - describe('parse()', () => { - let parsed; beforeEach(() => { @@ -42,11 +40,9 @@ describe('helpers.url', () => { it('extracts the host', () => { expect(parsed).to.have.property('host', 'example.com:3000'); }); - }); describe('format()', () => { - it('formats an object in to a URL', () => { expect(format({ protocol: 'http', @@ -63,7 +59,5 @@ describe('helpers.url', () => { hostname: 'example.com' })).to.equal('http://example.com'); }); - }); - }); diff --git a/test/spec/utils_spec.js b/test/spec/utils_spec.js index faa7aaae13a..2bbdcbaf6e6 100755 --- a/test/spec/utils_spec.js +++ b/test/spec/utils_spec.js @@ -4,21 +4,19 @@ var assert = require('assert'); var utils = require('../../src/utils'); describe('Utils', function () { - var obj_string = 's', - obj_number = 1, - obj_object = {}, - obj_array = [], - obj_function = function () {}; + obj_number = 1, + obj_object = {}, + obj_array = [], + obj_function = function () {}; var type_string = 'String', - type_number = 'Number', - type_object = 'Object', - type_array = 'Array', - type_function = 'Function'; + type_number = 'Number', + type_object = 'Object', + type_array = 'Array', + type_function = 'Function'; describe('replaceTokenInString', function () { - it('should replace all given tokens in a String', function () { var tokensToReplace = { foo: 'bar', @@ -81,8 +79,8 @@ describe('Utils', function () { describe('parseQueryStringParameters', function () { it('should append query string to existing using the input obj', function () { var obj = { - a:'1', - b:'2' + a: '1', + b: '2' }; var output = utils.parseQueryStringParameters(obj); @@ -116,18 +114,18 @@ describe('Utils', function () { describe('extend', function () { it('should merge two input object', function () { var target = { - a:'1', - b:'2' + a: '1', + b: '2' }; var source = { - c:'3' + c: '3' }; var expectedResult = { - a:'1', - b:'2', - c:'3' + a: '1', + b: '2', + c: '3' }; var output = Object.assign(target, source); @@ -137,7 +135,7 @@ describe('Utils', function () { it('should merge two input object even though target object is empty', function () { var target = {}; var source = { - c:'3' + c: '3' }; var output = Object.assign(target, source); @@ -146,8 +144,8 @@ describe('Utils', function () { it('just return target object, if the source object is empty', function () { var target = { - a:'1', - b:'2' + a: '1', + b: '2' }; var source = {}; @@ -157,7 +155,6 @@ describe('Utils', function () { }); describe('parseSizesInput', function () { - it('should return query string using multi size array', function () { var sizes = [[728, 90], [970, 90]]; var output = utils.parseSizesInput(sizes); @@ -184,7 +181,6 @@ describe('Utils', function () { }); describe('parseGPTSingleSizeArray', function () { - it('should return size string with input single size array', function () { var size = [300, 250]; var output = utils.parseGPTSingleSizeArray(size); @@ -333,7 +329,6 @@ describe('Utils', function () { var output = utils.isStr(obj_function); assert.deepEqual(output, false); }); - }); describe('isArray', function () { @@ -361,7 +356,6 @@ describe('Utils', function () { var output = utils.isArray(obj_function); assert.deepEqual(output, false); }); - }); describe('isEmpty', function () { @@ -371,7 +365,7 @@ describe('Utils', function () { }); it('should return false with non-empty object', function () { - var obj = { a:'b' }; + var obj = { a: 'b' }; var output = utils.isEmpty(obj); assert.deepEqual(output, false); }); @@ -410,24 +404,24 @@ describe('Utils', function () { }); it('return value array with vaild input object', function () { - var input = { a:'A', b:'B' }; - var callback = function (v) {return v;}; + var input = { a: 'A', b: 'B' }; + var callback = function (v) { return v; }; var output = utils._map(input, callback); assert.deepEqual(output, ['A', 'B']); }); it('return value array with vaild input object_callback func changed 1', function () { - var input = { a:'A', b:'B' }; - var callback = function (v, k) {return v + k;}; + var input = { a: 'A', b: 'B' }; + var callback = function (v, k) { return v + k; }; var output = utils._map(input, callback); assert.deepEqual(output, ['Aa', 'Bb']); }); it('return value array with vaild input object_callback func changed 2', function () { - var input = { a:'A', b:'B' }; - var callback = function (v, k, o) {return o;}; + var input = { a: 'A', b: 'B' }; + var callback = function (v, k, o) { return o; }; var output = utils._map(input, callback); assert.deepEqual(output, [input, input]); @@ -522,13 +516,12 @@ describe('Utils', function () { describe('polyfill test', function () { it('should not add polyfill to array', function() { - var arr = ['hello','world']; + var arr = ['hello', 'world']; var count = 0; - for(var key in arr) { + for (var key in arr) { count++; } - assert.equal(arr.length, count, "Polyfill test fails") + assert.equal(arr.length, count, 'Polyfill test fails') }); }); - }); diff --git a/test/spec/videoCache_spec.js b/test/spec/videoCache_spec.js new file mode 100644 index 00000000000..935841d2208 --- /dev/null +++ b/test/spec/videoCache_spec.js @@ -0,0 +1,94 @@ +import 'mocha'; +import chai from 'chai'; +import { store } from 'src/videoCache'; + +const should = chai.should(); + +describe('The video cache', () => { + function assertError(callbackSpy) { + callbackSpy.calledOnce.should.equal(true); + callbackSpy.firstCall.args[0].should.be.an('error'); + } + + function assertSuccess(callbackSpy) { + callbackSpy.calledOnce.should.equal(true); + should.not.exist(callbackSpy.firstCall.args[0]); + } + + describe('when the cache server is unreachable', () => { + let xhr; + let requests; + + beforeEach(() => { + xhr = sinon.useFakeXMLHttpRequest(); + requests = []; + xhr.onCreate = (request) => requests.push(request); + }); + + afterEach(() => xhr.restore()); + + it('should execute the callback with an error when store() is called', () => { + const callback = sinon.spy(); + store([ { vastUrl: 'my-mock-url.com' } ], callback); + + requests[0].respond(503, { + 'Content-Type': 'plain/text', + }, 'The server could not save anything at the moment.'); + + assertError(callback); + callback.firstCall.args[1].should.deep.equal([]); + }); + }); + + describe('when the cache server is available', () => { + let xhr; + let requests; + + beforeEach(() => { + xhr = sinon.useFakeXMLHttpRequest(); + requests = []; + xhr.onCreate = (request) => requests.push(request); + }); + + afterEach(() => xhr.restore()); + + it('should make the expected request when store() is called', () => { + store([ { vastUrl: 'my-mock-url.com' } ], function() { }); + + const request = requests[0]; + request.method.should.equal('POST'); + request.url.should.equal('https://prebid.adnxs.com/pbc/v1/cache'); + request.requestHeaders['Content-Type'].should.equal('text/plain;charset=utf-8'); + + JSON.parse(request.requestBody).should.deep.equal({ + puts: [{ + type: 'xml', + value: ` + + + prebid.org wrapper + + + + + + `, + }], + }); + }); + + it('should execute the callback with a successful result when store() is called', () => { + const callback = sinon.spy(); + store([ { vastUrl: 'my-mock-url.com' } ], callback); + requests[0].respond( + 200, + { + 'Content-Type': 'application/json', + }, + '{"responses":[{"uuid":"c488b101-af3e-4a99-b538-00423e5a3371"}]}'); + + assertSuccess(callback); + callback.firstCall.args[1].should.deep.equal([{ uuid: 'c488b101-af3e-4a99-b538-00423e5a3371' }]); + }); + }); +}); diff --git a/webpack.conf.js b/webpack.conf.js index 804054e1c57..d4a9b39dc20 100644 --- a/webpack.conf.js +++ b/webpack.conf.js @@ -1,42 +1,67 @@ var prebid = require('./package.json'); var StringReplacePlugin = require('string-replace-webpack-plugin'); var path = require('path'); +var webpack = require('webpack'); +var helpers = require('./gulpHelpers'); +var RequireEnsureWithoutJsonp = require('./plugins/RequireEnsureWithoutJsonp.js'); + +// list of module names to never include in the common bundle chunk +var neverBundle = [ + 'AnalyticsAdapter.js' +]; module.exports = { - output: { - filename: 'prebid.js' - }, devtool: 'source-map', resolve: { - modulesDirectories: ['', 'node_modules', 'src'] + modules: [ + path.resolve('.'), + 'node_modules' + ] }, resolveLoader: { - modulesDirectories: ['loaders', 'node_modules'] + modules: [ + path.resolve('./loaders'), + path.resolve('./node_modules') + ] + }, + output: { + jsonpFunction: 'pbjsChunk' }, module: { - loaders: [ + rules: [ { - test: /\.js$/, - include: /(src|test)/, - exclude: path.resolve(__dirname, 'node_modules'), - loader: 'babel', // 'babel-loader' is also a legal name to reference - query: { - presets: ['es2015'] - } + test: /.js$/, + include: /modules/, + exclude: /node_modules/, + use: [{ loader: 'delimiterLoader' }] }, { - test: /\.json$/, - loader: 'json' + test: /\.js$/, + exclude: path.resolve('./node_modules'), // required to prevent loader from choking non-Prebid.js node_modules + use: [ + { + loader: 'babel-loader', + options: { + presets: ['es2015'] + } + } + ] }, - { - test: /adaptermanager.js/, - include: /(src)/, - loader: 'analyticsLoader' + { // This makes sure babel-loader is ran on our intended Prebid.js modules that happen to be in node_modules + test: /\.js$/, + include: helpers.getArgModules().map(module => new RegExp('node_modules/' + module + '/')), + use: [ + { + loader: 'babel-loader', + options: { + presets: ['es2015'] + } + } + ], }, { - test: /adaptermanager.js/, - include: /(src)/, - loader: 'adapterLoader' + test: /\.json$/, + loader: 'json-loader' }, { test: /constants.json$/, @@ -52,23 +77,33 @@ module.exports = { ] }) }, - { - test: /\.js$/, - include: /(src|test|integrationExamples)/, - loader: StringReplacePlugin.replace({ - replacements: [ - { - pattern: /\$\$PREBID_GLOBAL\$\$/g, - replacement: function (match, p1, offset, string) { - return prebid.globalVarName; - } + { + test: /\.js$/, + include: /(src|test|modules|integrationExamples)/, + loader: StringReplacePlugin.replace({ + replacements: [ + { + pattern: /\$\$PREBID_GLOBAL\$\$/g, + replacement: function (match, p1, offset, string) { + return prebid.globalVarName; } - ] - }) - } + } + ] + }) + } ] }, plugins: [ - new StringReplacePlugin() + new StringReplacePlugin(), + new RequireEnsureWithoutJsonp(), + + // this plugin must be last so it can be easily removed for karma unit tests + new webpack.optimize.CommonsChunkPlugin({ + name: 'prebid', + filename: 'prebid-core.js', + minChunks: function(module, count) { + return !(count < 2 || neverBundle.includes(path.basename(module.resource))) + } + }) ] }; diff --git a/yarn.lock b/yarn.lock index a64bddaef4d..ec49039d1d0 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,9 +2,22 @@ # yarn lockfile v1 -"JSV@>= 4.0.x": - version "4.0.2" - resolved "https://registry.yarnpkg.com/JSV/-/JSV-4.0.2.tgz#d077f6825571f82132f9dffaed587b4029feff57" +"@gulp-sourcemaps/identity-map@1.X": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@gulp-sourcemaps/identity-map/-/identity-map-1.0.1.tgz#cfa23bc5840f9104ce32a65e74db7e7a974bbee1" + dependencies: + acorn "^5.0.3" + css "^2.2.1" + normalize-path "^2.1.1" + source-map "^0.5.6" + through2 "^2.0.3" + +"@gulp-sourcemaps/map-sources@1.X": + version "1.0.0" + resolved "https://registry.yarnpkg.com/@gulp-sourcemaps/map-sources/-/map-sources-1.0.0.tgz#890ae7c5d8c877f6d384860215ace9d7ec945bda" + dependencies: + normalize-path "^2.0.1" + through2 "^2.0.3" abbrev@1, abbrev@1.0.x: version "1.0.9" @@ -24,19 +37,29 @@ accepts@~1.2.12, accepts@~1.2.13: mime-types "~2.1.6" negotiator "0.5.3" +acorn-dynamic-import@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/acorn-dynamic-import/-/acorn-dynamic-import-2.0.2.tgz#c752bd210bef679501b6c6cb7fc84f8f47158cc4" + dependencies: + acorn "^4.0.3" + acorn-jsx@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-3.0.1.tgz#afdf9488fb1ecefc8348f6fb22f464e32a58b36b" dependencies: acorn "^3.0.4" +acorn@4.X, acorn@^4.0.3: + version "4.0.13" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-4.0.13.tgz#105495ae5361d697bd195c825192e1ad7f253787" + acorn@^3.0.0, acorn@^3.0.4, acorn@^3.3.0: version "3.3.0" resolved "https://registry.yarnpkg.com/acorn/-/acorn-3.3.0.tgz#45e37fb39e8da3f25baee3ff5369e2bb5f22017a" -acorn@^4.0.3: - version "4.0.11" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-4.0.11.tgz#edcda3bd937e7556410d42ed5860f67399c794c0" +acorn@^5.0.0, acorn@^5.0.1, acorn@^5.0.3: + version "5.1.1" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.1.1.tgz#53fe161111f912ab999ee887a90a0bc52822fd75" adm-zip@~0.4.3: version "0.4.7" @@ -47,17 +70,34 @@ after@0.8.2: resolved "https://registry.yarnpkg.com/after/-/after-0.8.2.tgz#fedb394f9f0e02aa9768e702bda23b505fae7e1f" agent-base@2: - version "2.0.1" - resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-2.0.1.tgz#bd8f9e86a8eb221fffa07bd14befd55df142815e" + version "2.1.1" + resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-2.1.1.tgz#d6de10d5af6132d5bd692427d46fc538539094c7" dependencies: extend "~3.0.0" semver "~5.0.1" -ajv@^4.9.1: - version "4.11.5" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-4.11.5.tgz#b6ee74657b993a01dce44b7944d56f485828d5bd" +ajv-keywords@^1.0.0: + version "1.5.1" + resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-1.5.1.tgz#314dd0a4b3368fad3dfcdc54ede6171b886daf3c" + +ajv-keywords@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-2.1.0.tgz#a296e17f7bfae7c1ce4f7e0de53d29cb32162df0" + +ajv@^4.7.0, ajv@^4.9.1: + version "4.11.8" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-4.11.8.tgz#82ffb02b29e662ae53bdc20af15947706739c536" + dependencies: + co "^4.6.0" + json-stable-stringify "^1.0.1" + +ajv@^5.1.5, ajv@^5.2.0: + version "5.2.2" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-5.2.2.tgz#47c68d69e86f5d953103b0074a9430dc63da5e39" dependencies: co "^4.6.0" + fast-deep-equal "^1.0.0" + json-schema-traverse "^0.3.0" json-stable-stringify "^1.0.1" align-text@^0.1.1, align-text@^0.1.3: @@ -68,12 +108,6 @@ align-text@^0.1.1, align-text@^0.1.3: longest "^1.0.1" repeat-string "^1.5.2" -alter@~0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/alter/-/alter-0.2.0.tgz#c7588808617572034aae62480af26b1d4d1cb3cd" - dependencies: - stable "~0.1.3" - amdefine@>=0.0.4: version "1.0.1" resolved "https://registry.yarnpkg.com/amdefine/-/amdefine-1.0.1.tgz#4a5282ac164729e93619bcfd3ad151f817ce91f5" @@ -91,6 +125,10 @@ ansi-escape-sequences@^3.0.0: dependencies: array-back "^1.0.3" +ansi-escapes@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-2.0.0.tgz#5bae52be424878dd9783e8910e3fc2922e83c81b" + ansi-regex@^0.2.0, ansi-regex@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-0.2.1.tgz#0d8e946967a3d8143f93e24e298525fc1b2235f9" @@ -103,6 +141,10 @@ ansi-regex@^2.0.0: version "2.1.1" resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" +ansi-regex@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998" + ansi-styles@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-1.1.0.tgz#eaecbf66cd706882760b2f4691582b8f55d7a7de" @@ -111,9 +153,11 @@ ansi-styles@^2.2.1: version "2.2.1" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" -ansi-styles@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-1.0.0.tgz#cb102df1c56f5123eab8b67cd7b98027a0279178" +ansi-styles@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.1.0.tgz#09c202d5c917ec23188caa5c9cb9179cd9547750" + dependencies: + color-convert "^1.0.0" anymatch@^1.3.0: version "1.3.0" @@ -133,11 +177,42 @@ app-usage-stats@^0.4.0: test-value "^2.1.0" usage-stats "^0.8.2" +append-transform@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/append-transform/-/append-transform-0.4.0.tgz#d76ebf8ca94d276e247a36bad44a4b74ab611991" + dependencies: + default-require-extensions "^1.0.0" + aproba@^1.0.3: - version "1.1.1" - resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.1.1.tgz#95d3600f07710aa0e9298c726ad5ecf2eacbabab" + version "1.1.2" + resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.1.2.tgz#45c6629094de4e96f693ef7eab74ae079c240fc1" + +archiver-utils@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/archiver-utils/-/archiver-utils-1.3.0.tgz#e50b4c09c70bf3d680e32ff1b7994e9f9d895174" + dependencies: + glob "^7.0.0" + graceful-fs "^4.1.0" + lazystream "^1.0.0" + lodash "^4.8.0" + normalize-path "^2.0.0" + readable-stream "^2.0.0" + +archiver@1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/archiver/-/archiver-1.3.0.tgz#4f2194d6d8f99df3f531e6881f14f15d55faaf22" + dependencies: + archiver-utils "^1.3.0" + async "^2.0.0" + buffer-crc32 "^0.2.1" + glob "^7.0.0" + lodash "^4.8.0" + readable-stream "^2.0.0" + tar-stream "^1.5.0" + walkdir "^0.0.11" + zip-stream "^1.1.0" -archiver@~0.14.0, archiver@~0.14.3: +archiver@~0.14.3: version "0.14.4" resolved "https://registry.yarnpkg.com/archiver/-/archiver-0.14.4.tgz#5b9ddb9f5ee1ceef21cb8f3b020e6240ecb4315c" dependencies: @@ -155,13 +230,13 @@ archy@^1.0.0: resolved "https://registry.yarnpkg.com/archy/-/archy-1.0.0.tgz#f9c8c13757cc1dd7bc379ac77b2c62a5c2868c40" are-we-there-yet@~1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.2.tgz#80e470e95a084794fe1899262c5667c6e88de1b3" + version "1.1.4" + resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.4.tgz#bb5dca382bb94f05e15194373d16fd3ba1ca110d" dependencies: delegates "^1.0.0" - readable-stream "^2.0.0 || ^1.1.13" + readable-stream "^2.0.6" -argparse@^1.0.2, argparse@^1.0.7: +argparse@^1.0.7: version "1.0.9" resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.9.tgz#73d83bc263f86e97f8cc4f6bae1b0e90a7d22c86" dependencies: @@ -174,8 +249,8 @@ arr-diff@^2.0.0: arr-flatten "^1.0.1" arr-flatten@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.0.1.tgz#e5ffe54d45e19f32f216e91eb99c8ce892bb604b" + version "1.1.0" + resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.1.0.tgz#36048bbff4e7b47e136644316c99669ea5ae91f1" array-back@^1.0.2, array-back@^1.0.3, array-back@^1.0.4: version "1.0.4" @@ -187,6 +262,10 @@ array-differ@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/array-differ/-/array-differ-1.0.0.tgz#eff52e3758249d33be402b8bb8e564bb2b5d4031" +array-each@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/array-each/-/array-each-1.0.1.tgz#a794af0c05ab1752846ee753a1f211a05ba0c44f" + array-find-index@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/array-find-index/-/array-find-index-1.0.2.tgz#df010aa1287e164bbda6f9723b0a96a1ec4187a1" @@ -195,6 +274,10 @@ array-slice@^0.2.3: version "0.2.3" resolved "https://registry.yarnpkg.com/array-slice/-/array-slice-0.2.3.tgz#dd3cfb80ed7973a75117cdac69b0b99ec86186f5" +array-slice@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/array-slice/-/array-slice-1.0.0.tgz#e73034f00dcc1f40876008fd20feae77bd4b7c2f" + array-tools@^1.0.6, array-tools@^1.1.0, array-tools@^1.1.4, array-tools@^1.8.4: version "1.8.6" resolved "https://registry.yarnpkg.com/array-tools/-/array-tools-1.8.6.tgz#145771f7f9c94e98cc5ea4196a99b8323aee18ae" @@ -245,8 +328,16 @@ arrify@^1.0.0: resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d" asap@~2.0.3: - version "2.0.5" - resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.5.tgz#522765b50c3510490e52d7dcfe085ef9ba96958f" + version "2.0.6" + resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46" + +asn1.js@^4.0.0: + version "4.9.1" + resolved "https://registry.yarnpkg.com/asn1.js/-/asn1.js-4.9.1.tgz#48ba240b45a9280e94748990ba597d216617fd40" + dependencies: + bn.js "^4.0.0" + inherits "^2.0.1" + minimalistic-assert "^1.0.0" asn1@0.1.11: version "0.1.11" @@ -282,47 +373,41 @@ assertion-error@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/assertion-error/-/assertion-error-1.0.2.tgz#13ca515d86206da0bac66e834dd397d87581094c" -ast-traverse@~0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/ast-traverse/-/ast-traverse-0.1.1.tgz#69cf2b8386f19dcda1bb1e05d68fe359d8897de6" - -ast-types@0.8.12: - version "0.8.12" - resolved "https://registry.yarnpkg.com/ast-types/-/ast-types-0.8.12.tgz#a0d90e4351bb887716c83fd637ebf818af4adfcc" - -ast-types@0.9.6, ast-types@0.x.x: - version "0.9.6" - resolved "https://registry.yarnpkg.com/ast-types/-/ast-types-0.9.6.tgz#102c9e9e9005d3e7e3829bf0c4fa24ee862ee9b9" +ast-types@0.x.x: + version "0.9.12" + resolved "https://registry.yarnpkg.com/ast-types/-/ast-types-0.9.12.tgz#b136300d67026625ae15326982ca9918e5db73c9" async-each@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.1.tgz#19d386a1d9edc6e7c1c85d388aedbcc56d33602d" -async@0.2.x, async@~0.2.10, async@~0.2.6, async@~0.2.9: - version "0.2.10" - resolved "https://registry.yarnpkg.com/async/-/async-0.2.10.tgz#b6bbe0b0674b9d719708ca38de8c237cb526c3d1" - -async@0.9.0: - version "0.9.0" - resolved "https://registry.yarnpkg.com/async/-/async-0.9.0.tgz#ac3613b1da9bed1b47510bb4651b8931e47146c7" +async@1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/async/-/async-1.4.0.tgz#35f86f83c59e0421d099cd9a91d8278fb578c00d" async@1.x, async@^1.3.0, async@^1.4.0, async@^1.5.0: version "1.5.2" resolved "https://registry.yarnpkg.com/async/-/async-1.5.2.tgz#ec6a61ae56480c0c3cb241c95618e20892f9672a" +async@2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/async/-/async-2.0.1.tgz#b709cc0280a9c36f09f4536be823c838a9049e25" + dependencies: + lodash "^4.8.0" + async@^0.9.0, async@~0.9.0: version "0.9.2" resolved "https://registry.yarnpkg.com/async/-/async-0.9.2.tgz#aea74d5e61c1f899613bf64bda66d4c78f2fd17d" -async@^2.0.1: - version "2.3.0" - resolved "https://registry.yarnpkg.com/async/-/async-2.3.0.tgz#1013d1051047dd320fe24e494d5c66ecaf6147d9" +async@^2.0.0, async@^2.1.2, async@^2.1.4: + version "2.5.0" + resolved "https://registry.yarnpkg.com/async/-/async-2.5.0.tgz#843190fd6b7357a0b9e1c956edddd5ec8462b54d" dependencies: lodash "^4.14.0" -async@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/async/-/async-1.0.0.tgz#f8fc04ca3a13784ade9e1641af98578cfbd647a9" +async@~0.2.10, async@~0.2.6: + version "0.2.10" + resolved "https://registry.yarnpkg.com/async/-/async-0.2.10.tgz#b6bbe0b0674b9d719708ca38de8c237cb526c3d1" asynckit@^0.4.0: version "0.4.0" @@ -377,19 +462,19 @@ babel-core@6.22.0, babel-core@^6.0.0, babel-core@^6.0.2: source-map "^0.5.0" babel-core@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-core/-/babel-core-6.24.1.tgz#8c428564dce1e1f41fb337ec34f4c3b022b5ad83" + version "6.25.0" + resolved "https://registry.yarnpkg.com/babel-core/-/babel-core-6.25.0.tgz#7dd42b0463c742e9d5296deb3ec67a9322dad729" dependencies: babel-code-frame "^6.22.0" - babel-generator "^6.24.1" + babel-generator "^6.25.0" babel-helpers "^6.24.1" babel-messages "^6.23.0" babel-register "^6.24.1" babel-runtime "^6.22.0" - babel-template "^6.24.1" - babel-traverse "^6.24.1" - babel-types "^6.24.1" - babylon "^6.11.0" + babel-template "^6.25.0" + babel-traverse "^6.25.0" + babel-types "^6.25.0" + babylon "^6.17.2" convert-source-map "^1.1.0" debug "^2.1.1" json5 "^0.5.0" @@ -400,64 +485,13 @@ babel-core@^6.24.1: slash "^1.0.0" source-map "^0.5.0" -babel-core@~5.8.3: - version "5.8.38" - resolved "https://registry.yarnpkg.com/babel-core/-/babel-core-5.8.38.tgz#1fcaee79d7e61b750b00b8e54f6dfc9d0af86558" - dependencies: - babel-plugin-constant-folding "^1.0.1" - babel-plugin-dead-code-elimination "^1.0.2" - babel-plugin-eval "^1.0.1" - babel-plugin-inline-environment-variables "^1.0.1" - babel-plugin-jscript "^1.0.4" - babel-plugin-member-expression-literals "^1.0.1" - babel-plugin-property-literals "^1.0.1" - babel-plugin-proto-to-assign "^1.0.3" - babel-plugin-react-constant-elements "^1.0.3" - babel-plugin-react-display-name "^1.0.3" - babel-plugin-remove-console "^1.0.1" - babel-plugin-remove-debugger "^1.0.1" - babel-plugin-runtime "^1.0.7" - babel-plugin-undeclared-variables-check "^1.0.2" - babel-plugin-undefined-to-void "^1.1.6" - babylon "^5.8.38" - bluebird "^2.9.33" - chalk "^1.0.0" - convert-source-map "^1.1.0" - core-js "^1.0.0" - debug "^2.1.1" - detect-indent "^3.0.0" - esutils "^2.0.0" - fs-readdir-recursive "^0.1.0" - globals "^6.4.0" - home-or-tmp "^1.0.0" - is-integer "^1.0.4" - js-tokens "1.0.1" - json5 "^0.4.0" - lodash "^3.10.0" - minimatch "^2.0.3" - output-file-sync "^1.1.0" - path-exists "^1.0.0" - path-is-absolute "^1.0.0" - private "^0.1.6" - regenerator "0.8.40" - regexpu "^1.3.0" - repeating "^1.1.2" - resolve "^1.1.6" - shebang-regex "^1.0.0" - slash "^1.0.0" - source-map "^0.5.0" - source-map-support "^0.2.10" - to-fast-properties "^1.0.0" - trim-right "^1.0.0" - try-resolve "^1.0.0" - -babel-generator@^6.22.0, babel-generator@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-generator/-/babel-generator-6.24.1.tgz#e715f486c58ded25649d888944d52aa07c5d9497" +babel-generator@^6.18.0, babel-generator@^6.22.0, babel-generator@^6.25.0: + version "6.25.0" + resolved "https://registry.yarnpkg.com/babel-generator/-/babel-generator-6.25.0.tgz#33a1af70d5f2890aeb465a4a7793c1df6a9ea9fc" dependencies: babel-messages "^6.23.0" babel-runtime "^6.22.0" - babel-types "^6.24.1" + babel-types "^6.25.0" detect-indent "^4.0.0" jsesc "^1.3.0" lodash "^4.2.0" @@ -539,21 +573,13 @@ babel-helpers@^6.22.0, babel-helpers@^6.24.1: babel-runtime "^6.22.0" babel-template "^6.24.1" -babel-jscs@^2.0.0: - version "2.0.5" - resolved "https://registry.yarnpkg.com/babel-jscs/-/babel-jscs-2.0.5.tgz#0a347046b48145acbca56e8c8ed5f736bc54f9d0" - dependencies: - babel-core "~5.8.3" - lodash.assign "^3.2.0" - -babel-loader@6.4.1: - version "6.4.1" - resolved "https://registry.yarnpkg.com/babel-loader/-/babel-loader-6.4.1.tgz#0b34112d5b0748a8dcdbf51acf6f9bd42d50b8ca" +babel-loader@^7.1.1: + version "7.1.1" + resolved "https://registry.yarnpkg.com/babel-loader/-/babel-loader-7.1.1.tgz#b87134c8b12e3e4c2a94e0546085bc680a2b8488" dependencies: - find-cache-dir "^0.1.1" - loader-utils "^0.2.16" + find-cache-dir "^1.0.0" + loader-utils "^1.0.2" mkdirp "^0.5.1" - object-assign "^4.0.1" babel-messages@^6.22.0, babel-messages@^6.23.0: version "6.23.0" @@ -567,60 +593,6 @@ babel-plugin-check-es2015-constants@^6.22.0: dependencies: babel-runtime "^6.22.0" -babel-plugin-constant-folding@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/babel-plugin-constant-folding/-/babel-plugin-constant-folding-1.0.1.tgz#8361d364c98e449c3692bdba51eff0844290aa8e" - -babel-plugin-dead-code-elimination@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/babel-plugin-dead-code-elimination/-/babel-plugin-dead-code-elimination-1.0.2.tgz#5f7c451274dcd7cccdbfbb3e0b85dd28121f0f65" - -babel-plugin-eval@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/babel-plugin-eval/-/babel-plugin-eval-1.0.1.tgz#a2faed25ce6be69ade4bfec263f70169195950da" - -babel-plugin-inline-environment-variables@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/babel-plugin-inline-environment-variables/-/babel-plugin-inline-environment-variables-1.0.1.tgz#1f58ce91207ad6a826a8bf645fafe68ff5fe3ffe" - -babel-plugin-jscript@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/babel-plugin-jscript/-/babel-plugin-jscript-1.0.4.tgz#8f342c38276e87a47d5fa0a8bd3d5eb6ccad8fcc" - -babel-plugin-member-expression-literals@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/babel-plugin-member-expression-literals/-/babel-plugin-member-expression-literals-1.0.1.tgz#cc5edb0faa8dc927170e74d6d1c02440021624d3" - -babel-plugin-property-literals@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/babel-plugin-property-literals/-/babel-plugin-property-literals-1.0.1.tgz#0252301900192980b1c118efea48ce93aab83336" - -babel-plugin-proto-to-assign@^1.0.3: - version "1.0.4" - resolved "https://registry.yarnpkg.com/babel-plugin-proto-to-assign/-/babel-plugin-proto-to-assign-1.0.4.tgz#c49e7afd02f577bc4da05ea2df002250cf7cd123" - dependencies: - lodash "^3.9.3" - -babel-plugin-react-constant-elements@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/babel-plugin-react-constant-elements/-/babel-plugin-react-constant-elements-1.0.3.tgz#946736e8378429cbc349dcff62f51c143b34e35a" - -babel-plugin-react-display-name@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/babel-plugin-react-display-name/-/babel-plugin-react-display-name-1.0.3.tgz#754fe38926e8424a4e7b15ab6ea6139dee0514fc" - -babel-plugin-remove-console@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/babel-plugin-remove-console/-/babel-plugin-remove-console-1.0.1.tgz#d8f24556c3a05005d42aaaafd27787f53ff013a7" - -babel-plugin-remove-debugger@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/babel-plugin-remove-debugger/-/babel-plugin-remove-debugger-1.0.1.tgz#fd2ea3cd61a428ad1f3b9c89882ff4293e8c14c7" - -babel-plugin-runtime@^1.0.7: - version "1.0.7" - resolved "https://registry.yarnpkg.com/babel-plugin-runtime/-/babel-plugin-runtime-1.0.7.tgz#bf7c7d966dd56ecd5c17fa1cb253c9acb7e54aaf" - babel-plugin-transform-es2015-arrow-functions@^6.22.0: version "6.22.0" resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-arrow-functions/-/babel-plugin-transform-es2015-arrow-functions-6.22.0.tgz#452692cb711d5f79dc7f85e440ce41b9f244d221" @@ -820,16 +792,6 @@ babel-plugin-transform-strict-mode@^6.24.1: babel-runtime "^6.22.0" babel-types "^6.24.1" -babel-plugin-undeclared-variables-check@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/babel-plugin-undeclared-variables-check/-/babel-plugin-undeclared-variables-check-1.0.2.tgz#5cf1aa539d813ff64e99641290af620965f65dee" - dependencies: - leven "^1.0.2" - -babel-plugin-undefined-to-void@^1.1.6: - version "1.1.6" - resolved "https://registry.yarnpkg.com/babel-plugin-undefined-to-void/-/babel-plugin-undefined-to-void-1.1.6.tgz#7f578ef8b78dfae6003385d8417a61eda06e2f81" - babel-polyfill@^6.13.0: version "6.23.0" resolved "https://registry.yarnpkg.com/babel-polyfill/-/babel-polyfill-6.23.0.tgz#8364ca62df8eafb830499f699177466c3b03499d" @@ -886,62 +848,58 @@ babel-runtime@^6.18.0, babel-runtime@^6.22.0: core-js "^2.4.0" regenerator-runtime "^0.10.0" -babel-template@^6.22.0, babel-template@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-template/-/babel-template-6.24.1.tgz#04ae514f1f93b3a2537f2a0f60a5a45fb8308333" +babel-template@^6.16.0, babel-template@^6.22.0, babel-template@^6.24.1, babel-template@^6.25.0: + version "6.25.0" + resolved "https://registry.yarnpkg.com/babel-template/-/babel-template-6.25.0.tgz#665241166b7c2aa4c619d71e192969552b10c071" dependencies: babel-runtime "^6.22.0" - babel-traverse "^6.24.1" - babel-types "^6.24.1" - babylon "^6.11.0" + babel-traverse "^6.25.0" + babel-types "^6.25.0" + babylon "^6.17.2" lodash "^4.2.0" -babel-traverse@^6.22.0, babel-traverse@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-traverse/-/babel-traverse-6.24.1.tgz#ab36673fd356f9a0948659e7b338d5feadb31695" +babel-traverse@^6.18.0, babel-traverse@^6.22.0, babel-traverse@^6.24.1, babel-traverse@^6.25.0: + version "6.25.0" + resolved "https://registry.yarnpkg.com/babel-traverse/-/babel-traverse-6.25.0.tgz#2257497e2fcd19b89edc13c4c91381f9512496f1" dependencies: babel-code-frame "^6.22.0" babel-messages "^6.23.0" babel-runtime "^6.22.0" - babel-types "^6.24.1" - babylon "^6.15.0" + babel-types "^6.25.0" + babylon "^6.17.2" debug "^2.2.0" globals "^9.0.0" invariant "^2.2.0" lodash "^4.2.0" -babel-types@^6.19.0, babel-types@^6.22.0, babel-types@^6.24.1: - version "6.24.1" - resolved "https://registry.yarnpkg.com/babel-types/-/babel-types-6.24.1.tgz#a136879dc15b3606bda0d90c1fc74304c2ff0975" +babel-types@^6.18.0, babel-types@^6.19.0, babel-types@^6.22.0, babel-types@^6.24.1, babel-types@^6.25.0: + version "6.25.0" + resolved "https://registry.yarnpkg.com/babel-types/-/babel-types-6.25.0.tgz#70afb248d5660e5d18f811d91c8303b54134a18e" dependencies: babel-runtime "^6.22.0" esutils "^2.0.2" lodash "^4.2.0" to-fast-properties "^1.0.1" -babylon@^5.8.38: - version "5.8.38" - resolved "https://registry.yarnpkg.com/babylon/-/babylon-5.8.38.tgz#ec9b120b11bf6ccd4173a18bf217e60b79859ffd" - -babylon@^6.11.0, babylon@^6.15.0: - version "6.16.1" - resolved "https://registry.yarnpkg.com/babylon/-/babylon-6.16.1.tgz#30c5a22f481978a9e7f8cdfdf496b11d94b404d3" +babylon@^6.11.0, babylon@^6.17.2, babylon@^6.17.4: + version "6.17.4" + resolved "https://registry.yarnpkg.com/babylon/-/babylon-6.17.4.tgz#3e8b7402b88d22c3423e137a1577883b15ff869a" backo2@1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/backo2/-/backo2-1.0.2.tgz#31ab1ac8b129363463e35b3ebb69f4dfcfba7947" -balanced-match@^0.4.1: - version "0.4.2" - resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-0.4.2.tgz#cb3f3e3c732dc0f01ee70b403f302e61d7709838" +balanced-match@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" base64-arraybuffer@0.1.5: version "0.1.5" resolved "https://registry.yarnpkg.com/base64-arraybuffer/-/base64-arraybuffer-0.1.5.tgz#73926771923b5a19747ad666aa5cd4bf9c6e9ce8" base64-js@^1.0.2: - version "1.2.0" - resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.2.0.tgz#a39992d723584811982be5e290bb6a53d86700f1" + version "1.2.1" + resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.2.1.tgz#a91947da1f4a516ea38e5b4ec0ec3773675e0886" base64-url@1.2.1: version "1.2.1" @@ -959,7 +917,7 @@ basic-auth@~1.0.3: version "1.0.4" resolved "https://registry.yarnpkg.com/basic-auth/-/basic-auth-1.0.4.tgz#030935b01de7c9b94a824b29f3fccb750d3a5290" -batch@0.5.3, batch@^0.5.3: +batch@0.5.3: version "0.5.3" resolved "https://registry.yarnpkg.com/batch/-/batch-0.5.3.tgz#3f3414f380321743bfc1042f9a83ff1d5824d464" @@ -969,7 +927,7 @@ bcrypt-pbkdf@^1.0.0: dependencies: tweetnacl "^0.14.3" -beeper@^1.0.0, beeper@^1.1.0: +beeper@^1.0.0: version "1.1.1" resolved "https://registry.yarnpkg.com/beeper/-/beeper-1.1.1.tgz#e6d5ea8c5dad001304a70b22638447f69cb2f809" @@ -1004,11 +962,11 @@ bl@^0.9.0, bl@~0.9.0: dependencies: readable-stream "~1.0.26" -bl@~1.0.0: - version "1.0.3" - resolved "https://registry.yarnpkg.com/bl/-/bl-1.0.3.tgz#fc5421a28fd4226036c3b3891a66a25bc64d226e" +bl@^1.0.0: + version "1.2.1" + resolved "https://registry.yarnpkg.com/bl/-/bl-1.2.1.tgz#cac328f7bee45730d404b692203fcb590e172d5e" dependencies: - readable-stream "~2.0.5" + readable-stream "^2.0.5" blob@0.0.4: version "0.0.4" @@ -1024,28 +982,32 @@ block-stream@*: dependencies: inherits "~2.0.0" -bluebird@^2.9.27, bluebird@^2.9.30, bluebird@^2.9.33: - version "2.11.0" - resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-2.11.0.tgz#534b9033c022c9579c56ba3b3e5a5caafbb650e1" +bluebird@^3.3.0: + version "3.5.0" + resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.5.0.tgz#791420d7f551eea2897453a8a77653f96606d67c" bluebird@~3.4.6: version "3.4.7" resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.4.7.tgz#f72d760be09b7f76d08ed8fae98b289a8d05fab3" -body-parser@^1.12.4: - version "1.17.1" - resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.17.1.tgz#75b3bc98ddd6e7e0d8ffe750dfaca5c66993fa47" +bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.1.1, bn.js@^4.4.0: + version "4.11.7" + resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.11.7.tgz#ddb048e50d9482790094c13eb3fcfc833ce7ab46" + +body-parser@^1.16.1: + version "1.17.2" + resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.17.2.tgz#f8892abc8f9e627d42aedafbca66bf5ab99104ee" dependencies: bytes "2.4.0" content-type "~1.0.2" - debug "2.6.1" + debug "2.6.7" depd "~1.1.0" http-errors "~1.6.1" iconv-lite "0.4.15" on-finished "~2.3.0" qs "6.4.0" raw-body "~2.2.0" - type-is "~1.6.14" + type-is "~1.6.15" body-parser@~1.13.3: version "1.13.3" @@ -1089,11 +1051,11 @@ boom@2.x.x: dependencies: hoek "2.x.x" -brace-expansion@^1.0.0: - version "1.1.7" - resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.7.tgz#3effc3c50e000531fb720eaff80f0ae8ef23cf59" +brace-expansion@^1.0.0, brace-expansion@^1.1.7: + version "1.1.8" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.8.tgz#c07b211c7c952ec1f8efd51a77ef0d1d3990a292" dependencies: - balanced-match "^0.4.1" + balanced-match "^1.0.0" concat-map "0.0.1" braces@^0.1.2: @@ -1110,9 +1072,9 @@ braces@^1.8.2: preserve "^0.2.0" repeat-element "^1.1.2" -breakable@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/breakable/-/breakable-1.0.0.tgz#784a797915a38ead27bad456b5572cb4bbaa78c1" +brorand@^1.0.1: + version "1.1.0" + resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f" browser-stdout@1.3.0: version "1.3.0" @@ -1124,6 +1086,51 @@ browserify-aes@0.4.0: dependencies: inherits "^2.0.1" +browserify-aes@^1.0.0, browserify-aes@^1.0.4: + version "1.0.6" + resolved "https://registry.yarnpkg.com/browserify-aes/-/browserify-aes-1.0.6.tgz#5e7725dbdef1fd5930d4ebab48567ce451c48a0a" + dependencies: + buffer-xor "^1.0.2" + cipher-base "^1.0.0" + create-hash "^1.1.0" + evp_bytestokey "^1.0.0" + inherits "^2.0.1" + +browserify-cipher@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/browserify-cipher/-/browserify-cipher-1.0.0.tgz#9988244874bf5ed4e28da95666dcd66ac8fc363a" + dependencies: + browserify-aes "^1.0.4" + browserify-des "^1.0.0" + evp_bytestokey "^1.0.0" + +browserify-des@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/browserify-des/-/browserify-des-1.0.0.tgz#daa277717470922ed2fe18594118a175439721dd" + dependencies: + cipher-base "^1.0.1" + des.js "^1.0.0" + inherits "^2.0.1" + +browserify-rsa@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/browserify-rsa/-/browserify-rsa-4.0.1.tgz#21e0abfaf6f2029cf2fafb133567a701d4135524" + dependencies: + bn.js "^4.1.0" + randombytes "^2.0.1" + +browserify-sign@^4.0.0: + version "4.0.4" + resolved "https://registry.yarnpkg.com/browserify-sign/-/browserify-sign-4.0.4.tgz#aa4eb68e5d7b658baa6bf6a57e630cbd7a93d298" + dependencies: + bn.js "^4.1.1" + browserify-rsa "^4.0.0" + create-hash "^1.1.0" + create-hmac "^1.1.2" + elliptic "^6.0.0" + inherits "^2.0.1" + parse-asn1 "^5.0.0" + browserify-zlib@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/browserify-zlib/-/browserify-zlib-0.1.4.tgz#bb35f8a519f600e0fa6b8485241c979d0141fb2d" @@ -1136,21 +1143,22 @@ browserstack@1.5.0: dependencies: https-proxy-agent "1.0.0" -browserstacktunnel-wrapper@~1.4.2: - version "1.4.2" - resolved "https://registry.yarnpkg.com/browserstacktunnel-wrapper/-/browserstacktunnel-wrapper-1.4.2.tgz#6598fb7d784b6ff348e3df7c104b0d9c27ea5275" +browserstacktunnel-wrapper@~2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/browserstacktunnel-wrapper/-/browserstacktunnel-wrapper-2.0.1.tgz#ffe1910d6e39fe86618183e826690041af53edae" dependencies: + https-proxy-agent "^1.0.0" unzip "~0.1.9" -buffer-crc32@~0.2.1, buffer-crc32@~0.2.3: +buffer-crc32@^0.2.1, buffer-crc32@~0.2.1: version "0.2.13" resolved "https://registry.yarnpkg.com/buffer-crc32/-/buffer-crc32-0.2.13.tgz#0d333e3f00eac50aa1454abd30ef8c2a5d9a7242" -buffer-shims@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/buffer-shims/-/buffer-shims-1.0.0.tgz#9978ce317388c649ad8793028c3477ef044a8b51" +buffer-xor@^1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/buffer-xor/-/buffer-xor-1.0.3.tgz#26e61ed1422fb70dd42e6e36729ed51d855fe8d9" -buffer@^4.9.0: +buffer@^4.3.0, buffer@^4.9.0: version "4.9.1" resolved "https://registry.yarnpkg.com/buffer/-/buffer-4.9.1.tgz#6d1bb601b07a4efced97094132093027c95bc298" dependencies: @@ -1162,7 +1170,7 @@ buffers@~0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/buffers/-/buffers-0.1.1.tgz#b24579c3bed4d6d396aeee6d9a8ae7f5482ab7bb" -builtin-modules@^1.0.0: +builtin-modules@^1.0.0, builtin-modules@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-1.1.1.tgz#270f076c5a72c02f5b65a47df94c5fe3a278892f" @@ -1192,10 +1200,20 @@ cache-point@~0.3.3: fs-then-native "^1.0.2" mkdirp "~0.5.1" +caller-path@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/caller-path/-/caller-path-0.1.0.tgz#94085ef63581ecd3daa92444a8fe94e82577751f" + dependencies: + callsites "^0.2.0" + callsite@1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/callsite/-/callsite-1.0.0.tgz#280398e5d664bd74038b6f0905153e6e8af1bc20" +callsites@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/callsites/-/callsites-0.2.0.tgz#afab96262910a7f33c19a5775825c69f34e350ca" + camelcase-keys@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/camelcase-keys/-/camelcase-keys-2.1.0.tgz#308beeaffdf28119051efa1d932213c91b8f92e7" @@ -1227,13 +1245,9 @@ caseless@~0.8.0: version "0.8.0" resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.8.0.tgz#5bca2881d41437f54b2407ebe34888c7b9ad4f7d" -caseless@~0.9.0: - version "0.9.0" - resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.9.0.tgz#b7b65ce6bf1413886539cfd533f0b30effa9cf88" - catharsis@~0.8.8: - version "0.8.8" - resolved "https://registry.yarnpkg.com/catharsis/-/catharsis-0.8.8.tgz#693479f43aac549d806bd73e924cd0d944951a06" + version "0.8.9" + resolved "https://registry.yarnpkg.com/catharsis/-/catharsis-0.8.9.tgz#98cc890ca652dd2ef0e70b37925310ff9e90fc8b" dependencies: underscore-contrib "~0.3.0" @@ -1275,7 +1289,7 @@ chalk@^0.5.0: strip-ansi "^0.3.0" supports-color "^0.2.0" -chalk@^1.0.0, chalk@^1.1.0, chalk@^1.1.1, chalk@~1.1.0: +chalk@^1.0.0, chalk@^1.1.0, chalk@^1.1.1, chalk@^1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" dependencies: @@ -1285,17 +1299,17 @@ chalk@^1.0.0, chalk@^1.1.0, chalk@^1.1.1, chalk@~1.1.0: strip-ansi "^3.0.0" supports-color "^2.0.0" -chalk@~0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-0.4.0.tgz#5199a3ddcd0c1efe23bc08c1b027b06176e0c64f" +chalk@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.0.1.tgz#dbec49436d2ae15f536114e76d14656cdbc0f44d" dependencies: - ansi-styles "~1.0.0" - has-color "~0.1.0" - strip-ansi "~0.1.0" + ansi-styles "^3.1.0" + escape-string-regexp "^1.0.5" + supports-color "^4.0.0" -chokidar@^1.0.0, chokidar@^1.4.1: - version "1.6.1" - resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-1.6.1.tgz#2f4447ab5e96e50fb3d789fd90d4c72e0e4c70c2" +chokidar@^1.0.0, chokidar@^1.4.1, chokidar@^1.4.3: + version "1.7.0" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-1.7.0.tgz#798e689778151c8076b4b360e5edd28cda2bb468" dependencies: anymatch "^1.3.0" async-each "^1.0.0" @@ -1308,6 +1322,17 @@ chokidar@^1.0.0, chokidar@^1.4.1: optionalDependencies: fsevents "^1.0.0" +cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/cipher-base/-/cipher-base-1.0.4.tgz#8760e4ecc272f4c363532f926d874aae2c1397de" + dependencies: + inherits "^2.0.1" + safe-buffer "^5.0.1" + +circular-json@^0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/circular-json/-/circular-json-0.3.1.tgz#be8b36aefccde8b3ca7aa2d6afc07a37242c0d2d" + cli-commands@0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/cli-commands/-/cli-commands-0.1.0.tgz#c57cacc406bbcf9ee21646607161ed432ef5a05a" @@ -1317,22 +1342,19 @@ cli-commands@0.1.0: command-line-commands "^1.0.4" command-line-usage "^3.0.5" -cli-table@~0.3.1: - version "0.3.1" - resolved "https://registry.yarnpkg.com/cli-table/-/cli-table-0.3.1.tgz#f53b05266a8b1a0b934b3d0821e6e2dc5914ae23" +cli-cursor@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-2.1.0.tgz#b35dac376479facc3e94747d41d0d0f5238ffcb5" dependencies: - colors "1.0.3" + restore-cursor "^2.0.0" cli-width@^1.0.1: version "1.1.1" resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-1.1.1.tgz#a4d293ef67ebb7b88d4a4d42c0ccf00c4d1e366d" -cli@~1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/cli/-/cli-1.0.1.tgz#22817534f24bfa4950c34d532d48ecbc621b8c14" - dependencies: - exit "0.1.2" - glob "^7.1.1" +cli-width@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-2.1.0.tgz#b234ca209b29ef66fc518d9b98d5847b00edf00a" cliui@^2.1.0: version "2.1.0" @@ -1370,6 +1392,10 @@ clone@^1.0.0, clone@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/clone/-/clone-1.0.2.tgz#260b7a99ebb1edfe247538175f783243cb19d149" +clone@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/clone/-/clone-2.1.1.tgz#d217d1e961118e3ac9a4b8bba3285553bf647cdb" + cloneable-readable@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/cloneable-readable/-/cloneable-readable-1.0.0.tgz#a6290d413f217a61232f95e458ff38418cfb0117" @@ -1390,18 +1416,12 @@ code-point-at@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" -coffee-script@~1.8.0: - version "1.8.0" - resolved "https://registry.yarnpkg.com/coffee-script/-/coffee-script-1.8.0.tgz#9c9f1d2b4a52a000ded15b659791703648263c1d" - dependencies: - mkdirp "~0.3.5" - collect-all@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/collect-all/-/collect-all-1.0.2.tgz#39450f1e7aa6086570a006bce93ccf1218a77ea1" + version "1.0.3" + resolved "https://registry.yarnpkg.com/collect-all/-/collect-all-1.0.3.tgz#1abcc20448b58a1447487fcf34130e9512b0acf8" dependencies: stream-connect "^1.0.2" - stream-via "^1.0.3" + stream-via "^1.0.4" collect-all@~0.2.1: version "0.2.1" @@ -1419,15 +1439,17 @@ collect-json@^1.0.1, collect-json@^1.0.7, collect-json@^1.0.8: stream-connect "^1.0.2" stream-via "^1.0.3" -colors@0.6.x: - version "0.6.2" - resolved "https://registry.yarnpkg.com/colors/-/colors-0.6.2.tgz#2423fe6678ac0c5dae8852e5d0e5be08c997abcc" +color-convert@^1.0.0: + version "1.9.0" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.0.tgz#1accf97dd739b983bf994d56fec8f95853641b7a" + dependencies: + color-name "^1.1.1" -colors@1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/colors/-/colors-1.0.3.tgz#0433f44d809680fdeb60ed260f1b0c262e82a40b" +color-name@^1.1.1: + version "1.1.2" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.2.tgz#5c8ab72b64bd2215d617ae9559ebb148475cf98d" -colors@^1.1.0: +colors@^1.1.0, colors@^1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/colors/-/colors-1.1.2.tgz#168a4701756b6a7f51a12ce0c97bfa28c084ed63" @@ -1446,6 +1468,12 @@ column-layout@^2.1.1: typical "^2.4.2" wordwrapjs "^1.2.0" +combine-lists@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/combine-lists/-/combine-lists-1.0.1.tgz#458c07e09e0d900fc28b70a3fec2dacd1d2cb7f6" + dependencies: + lodash "^4.5.0" + combined-stream@^1.0.5, combined-stream@~1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.5.tgz#938370a57b4a51dea2c77c15d5c5fdf895164009" @@ -1532,18 +1560,12 @@ commander@2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/commander/-/commander-2.3.0.tgz#fd430e889832ec353b9acd1de217c11cb3eef873" -commander@2.9.0, commander@^2.5.0, commander@^2.8.1, commander@^2.9.0, commander@~2.9.0: +commander@2.9.0, commander@^2.9.0, commander@~2.9.0: version "2.9.0" resolved "https://registry.yarnpkg.com/commander/-/commander-2.9.0.tgz#9c99094176e12240cb22d6c5146098400fe0f7d4" dependencies: graceful-readlink ">= 1.0.0" -comment-parser@^0.3.1: - version "0.3.1" - resolved "https://registry.yarnpkg.com/comment-parser/-/comment-parser-0.3.1.tgz#fd657aac8c1492d308c9a6100fc9b49d2435aba1" - dependencies: - readable-stream "^2.0.4" - common-sequence@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/common-sequence/-/common-sequence-1.0.2.tgz#30e07f3f8f6f7f9b3dee854f20b2d39eee086de8" @@ -1552,20 +1574,6 @@ commondir@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b" -commoner@~0.10.3: - version "0.10.8" - resolved "https://registry.yarnpkg.com/commoner/-/commoner-0.10.8.tgz#34fc3672cd24393e8bb47e70caa0293811f4f2c5" - dependencies: - commander "^2.5.0" - detective "^4.3.1" - glob "^5.0.15" - graceful-fs "^4.1.2" - iconv-lite "^0.4.5" - mkdirp "^0.5.0" - private "^0.1.6" - q "^1.1.2" - recast "^0.11.17" - component-bind@1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/component-bind/-/component-bind-1.0.0.tgz#00c608ab7dcd93897c0009651b1d3a8e1e73bbd1" @@ -1582,6 +1590,15 @@ component-inherit@0.0.3: version "0.0.3" resolved "https://registry.yarnpkg.com/component-inherit/-/component-inherit-0.0.3.tgz#645fc4adf58b72b649d5cae65135619db26ff143" +compress-commons@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/compress-commons/-/compress-commons-1.2.0.tgz#58587092ef20d37cb58baf000112c9278ff73b9f" + dependencies: + buffer-crc32 "^0.2.1" + crc32-stream "^2.0.0" + normalize-path "^2.0.0" + readable-stream "^2.0.0" + compress-commons@~0.2.0: version "0.2.9" resolved "https://registry.yarnpkg.com/compress-commons/-/compress-commons-0.2.9.tgz#422d927430c01abd06cd455b6dfc04cb4cf8003c" @@ -1612,15 +1629,7 @@ concat-map@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" -concat-stream@1.5.0: - version "1.5.0" - resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.5.0.tgz#53f7d43c51c5e43f81c8fdd03321c631be68d611" - dependencies: - inherits "~2.0.1" - readable-stream "~2.0.0" - typedarray "~0.0.5" - -concat-stream@^1.4.7, concat-stream@^1.5.1: +concat-stream@^1.5.1, concat-stream@^1.6.0: version "1.6.0" resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.0.tgz#0aac662fd52be78964d5532f694784e70110acf7" dependencies: @@ -1691,16 +1700,16 @@ connect@^2.30.0: utils-merge "1.0.0" vhost "~3.0.1" -connect@^3.3.5: - version "3.6.0" - resolved "https://registry.yarnpkg.com/connect/-/connect-3.6.0.tgz#f09a4f7dcd17324b663b725c815bdb1c4158a46e" +connect@^3.6.0: + version "3.6.2" + resolved "https://registry.yarnpkg.com/connect/-/connect-3.6.2.tgz#694e8d20681bfe490282c8ab886be98f09f42fe7" dependencies: - debug "2.6.1" - finalhandler "1.0.0" + debug "2.6.7" + finalhandler "1.0.3" parseurl "~1.3.1" utils-merge "1.0.0" -console-browserify@1.1.x, console-browserify@^1.1.0: +console-browserify@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/console-browserify/-/console-browserify-1.1.0.tgz#f0241c45730a9fc6323b206dbf38edc741d0bb10" dependencies: @@ -1714,11 +1723,15 @@ constants-browserify@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/constants-browserify/-/constants-browserify-1.0.0.tgz#c20b96d8c617748aaf1c16021760cd27fcb8cb75" +contains-path@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/contains-path/-/contains-path-0.1.0.tgz#fe8cf184ff6670b6baef01a9d4861a5cbec4120a" + content-type@~1.0.1, content-type@~1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.2.tgz#b7d113aee7a8dd27bd21133c4dc2529df1721eed" -convert-source-map@^1.1.0: +convert-source-map@1.X, convert-source-map@^1.1.0, convert-source-map@^1.3.0: version "1.5.0" resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.5.0.tgz#9acd70851c6d5dfdd93d9282e5edf94a03ff46b5" @@ -1741,11 +1754,7 @@ cookie@0.3.1: version "0.3.1" resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.3.1.tgz#e7e0a1f9ef43b4c8ba925c5c5a96e806d16873bb" -core-js@^1.0.0: - version "1.2.7" - resolved "https://registry.yarnpkg.com/core-js/-/core-js-1.2.7.tgz#652294c14651db28fa93bd2d5ff2983a4f08c636" - -core-js@^2.0.1, core-js@^2.1.0, core-js@^2.4.0, core-js@^2.4.1: +core-js@^2.0.1, core-js@^2.2.0, core-js@^2.4.0, core-js@^2.4.1: version "2.4.1" resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.4.1.tgz#4de911e667b0eae9124e34254b53aea6fc618d3e" @@ -1754,8 +1763,8 @@ core-util-is@~1.0.0: resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" coveralls@^2.11.11: - version "2.13.0" - resolved "https://registry.yarnpkg.com/coveralls/-/coveralls-2.13.0.tgz#df933876e8c6f478efb04f4d3ab70dc96b7e5a8e" + version "2.13.1" + resolved "https://registry.yarnpkg.com/coveralls/-/coveralls-2.13.1.tgz#d70bb9acc1835ec4f063ff9dac5423c17b11f178" dependencies: js-yaml "3.6.1" lcov-parse "0.0.10" @@ -1763,6 +1772,13 @@ coveralls@^2.11.11: minimist "1.2.0" request "2.79.0" +crc32-stream@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/crc32-stream/-/crc32-stream-2.0.0.tgz#e3cdd3b4df3168dd74e3de3fbbcb7b297fe908f4" + dependencies: + crc "^3.4.4" + readable-stream "^2.0.0" + crc32-stream@~0.3.1: version "0.3.4" resolved "https://registry.yarnpkg.com/crc32-stream/-/crc32-stream-0.3.4.tgz#73bc25b45fac1db6632231a7bfce8927e9f06552" @@ -1774,6 +1790,37 @@ crc@3.3.0: version "3.3.0" resolved "https://registry.yarnpkg.com/crc/-/crc-3.3.0.tgz#fa622e1bc388bf257309082d6b65200ce67090ba" +crc@^3.4.4: + version "3.4.4" + resolved "https://registry.yarnpkg.com/crc/-/crc-3.4.4.tgz#9da1e980e3bd44fc5c93bf5ab3da3378d85e466b" + +create-ecdh@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/create-ecdh/-/create-ecdh-4.0.0.tgz#888c723596cdf7612f6498233eebd7a35301737d" + dependencies: + bn.js "^4.1.0" + elliptic "^6.0.0" + +create-hash@^1.1.0, create-hash@^1.1.1, create-hash@^1.1.2: + version "1.1.3" + resolved "https://registry.yarnpkg.com/create-hash/-/create-hash-1.1.3.tgz#606042ac8b9262750f483caddab0f5819172d8fd" + dependencies: + cipher-base "^1.0.1" + inherits "^2.0.1" + ripemd160 "^2.0.0" + sha.js "^2.4.0" + +create-hmac@^1.1.0, create-hmac@^1.1.2, create-hmac@^1.1.4: + version "1.1.6" + resolved "https://registry.yarnpkg.com/create-hmac/-/create-hmac-1.1.6.tgz#acb9e221a4e17bdb076e90657c42b93e3726cf06" + dependencies: + cipher-base "^1.0.3" + create-hash "^1.1.0" + inherits "^2.0.1" + ripemd160 "^2.0.0" + safe-buffer "^5.0.1" + sha.js "^2.4.8" + cryptiles@0.2.x: version "0.2.2" resolved "https://registry.yarnpkg.com/cryptiles/-/cryptiles-0.2.2.tgz#ed91ff1f17ad13d3748288594f8a48a0d26f325c" @@ -1795,6 +1842,21 @@ crypto-browserify@3.3.0: ripemd160 "0.2.0" sha.js "2.2.6" +crypto-browserify@^3.11.0: + version "3.11.1" + resolved "https://registry.yarnpkg.com/crypto-browserify/-/crypto-browserify-3.11.1.tgz#948945efc6757a400d6e5e5af47194d10064279f" + dependencies: + browserify-cipher "^1.0.0" + browserify-sign "^4.0.0" + create-ecdh "^4.0.0" + create-hash "^1.1.0" + create-hmac "^1.1.0" + diffie-hellman "^5.0.0" + inherits "^2.0.1" + pbkdf2 "^3.0.3" + public-encrypt "^4.0.0" + randombytes "^2.0.0" + csrf@~3.0.0: version "3.0.6" resolved "https://registry.yarnpkg.com/csrf/-/csrf-3.0.6.tgz#b61120ddceeafc91e76ed5313bb5c0b2667b710a" @@ -1821,7 +1883,7 @@ css-value@~0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/css-value/-/css-value-0.0.1.tgz#5efd6c2eea5ea1fd6b6ac57ec0427b18452424ea" -css@^2.0.0: +css@2.X, css@^2.0.0, css@^2.2.1: version "2.2.1" resolved "https://registry.yarnpkg.com/css/-/css-2.2.1.tgz#73a4c81de85db664d4ee674f7d47085e3b2d55dc" dependencies: @@ -1857,17 +1919,13 @@ custom-event@~1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/custom-event/-/custom-event-1.0.1.tgz#5d02a46850adf1b4a317946a3928fccb5bfd0425" -cycle@1.0.x: - version "1.0.3" - resolved "https://registry.yarnpkg.com/cycle/-/cycle-1.0.3.tgz#21e80b2be8580f98b468f379430662b046c34ad2" - d@1: version "1.0.0" resolved "https://registry.yarnpkg.com/d/-/d-1.0.0.tgz#754bb5bfe55451da69a58b94d45f4c5b0462d58f" dependencies: es5-ext "^0.10.9" -dargs@christian-bromann/dargs: +"dargs@github:christian-bromann/dargs": version "4.0.1" resolved "https://codeload.github.com/christian-bromann/dargs/tar.gz/7d6d4164a7c4106dbd14ef39ed8d95b7b5e9b770" dependencies: @@ -1879,15 +1937,15 @@ dashdash@^1.12.0: dependencies: assert-plus "^1.0.0" -data-uri-to-buffer@0: - version "0.0.4" - resolved "https://registry.yarnpkg.com/data-uri-to-buffer/-/data-uri-to-buffer-0.0.4.tgz#46e13ab9da8e309745c8d01ce547213ebdb2fe3f" +data-uri-to-buffer@1: + version "1.0.0" + resolved "https://registry.yarnpkg.com/data-uri-to-buffer/-/data-uri-to-buffer-1.0.0.tgz#af963806bc2bb6253f75442f13dfbee68a2a5897" date-now@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/date-now/-/date-now-0.1.4.tgz#eaf439fd4d4848ad74e5cc7dbef200672b9e345b" -dateformat@^1.0.7-1.2.3, dateformat@~1.0.6: +dateformat@^1.0.7-1.2.3: version "1.0.12" resolved "https://registry.yarnpkg.com/dateformat/-/dateformat-1.0.12.tgz#9f124b67594c937ff706932e4a642cca8dbbfee9" dependencies: @@ -1911,15 +1969,19 @@ ddata@~0.1.25: string-tools "^1.0.0" test-value "^2.0.0" -debug@0.7.4: - version "0.7.4" - resolved "https://registry.yarnpkg.com/debug/-/debug-0.7.4.tgz#06e1ea8082c2cb14e39806e22e2f6f757f92af39" - -debug@2, debug@2.6.1: - version "2.6.1" - resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.1.tgz#79855090ba2c4e3115cc7d8769491d58f0491351" +debug-fabulous@0.1.X: + version "0.1.1" + resolved "https://registry.yarnpkg.com/debug-fabulous/-/debug-fabulous-0.1.1.tgz#1b970878c9fa4fbd1c88306eab323c830c58f1d6" dependencies: - ms "0.7.2" + debug "2.3.0" + memoizee "^0.4.5" + object-assign "4.1.0" + +debug@2, debug@2.6.8, debug@^2.1.1, debug@^2.2.0, debug@^2.6.3, debug@^2.6.8: + version "2.6.8" + resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.8.tgz#e731531ca2ede27d188222427da17821d68ff4fc" + dependencies: + ms "2.0.0" debug@2.0.0: version "2.0.0" @@ -1927,23 +1989,29 @@ debug@2.0.0: dependencies: ms "0.6.2" -debug@2.2.0, debug@^2.1.1, debug@^2.2.0, debug@~2.2.0: +debug@2.2.0, debug@~2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/debug/-/debug-2.2.0.tgz#f87057e995b1a1f6ae6a4960664137bc56f039da" dependencies: ms "0.7.1" +debug@2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/debug/-/debug-2.3.0.tgz#3912dc55d7167fc3af17d2b85c13f93deaedaa43" + dependencies: + ms "0.7.2" + debug@2.3.3: version "2.3.3" resolved "https://registry.yarnpkg.com/debug/-/debug-2.3.3.tgz#40c453e67e6e13c901ddec317af8986cda9eff8c" dependencies: ms "0.7.2" -debug@2.6.3: - version "2.6.3" - resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.3.tgz#0f7eb8c30965ec08c72accfa0130c8b79984141d" +debug@2.6.7: + version "2.6.7" + resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.7.tgz#92bad1f6d05bbb6bba22cca88bcd0ec894c2861e" dependencies: - ms "0.7.2" + ms "2.0.0" decamelize@^1.0.0, decamelize@^1.1.1, decamelize@^1.1.2: version "1.2.0" @@ -1955,22 +2023,24 @@ deep-eql@0.1.3, deep-eql@^0.1.3: dependencies: type-detect "0.1.1" -deep-equal@*: - version "1.0.1" - resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-1.0.1.tgz#f5d260292b660e084eff4cdbc9f08ad3247448b5" - deep-extend@~0.4.0, deep-extend@~0.4.1: - version "0.4.1" - resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.4.1.tgz#efe4113d08085f4e6f9687759810f807469e2253" + version "0.4.2" + resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.4.2.tgz#48b699c27e334bf89f10892be432f6e4c7d34a7f" -deep-is@~0.1.2: +deep-is@~0.1.3: version "0.1.3" resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" -"deepmerge@>=0.2.7 <0.3.0-0", deepmerge@^0.2.7, deepmerge@~0.2.7: +deepmerge@^0.2.7, deepmerge@~0.2.7: version "0.2.10" resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-0.2.10.tgz#8906bf9e525a4fbf1b203b2afcb4640249821219" +default-require-extensions@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/default-require-extensions/-/default-require-extensions-1.0.0.tgz#f37ea15d3e13ffd9b437d33e1a75b5fb97874cb8" + dependencies: + strip-bom "^2.0.0" + defaults@^1.0.0: version "1.0.3" resolved "https://registry.yarnpkg.com/defaults/-/defaults-1.0.3.tgz#c656051e9817d9ff08ed881477f3fe4019f3ef7d" @@ -1981,26 +2051,7 @@ defer-promise@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/defer-promise/-/defer-promise-1.0.1.tgz#1ca6ffeddbcef1715dd7aae25c7616f9ae22932f" -defined@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/defined/-/defined-1.0.0.tgz#c98d9bcef75674188e110969151199e39b1fa693" - -defs@~1.1.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/defs/-/defs-1.1.1.tgz#b22609f2c7a11ba7a3db116805c139b1caffa9d2" - dependencies: - alter "~0.2.0" - ast-traverse "~0.1.1" - breakable "~1.0.0" - esprima-fb "~15001.1001.0-dev-harmony-fb" - simple-fmt "~0.1.0" - simple-is "~0.2.0" - stringmap "~0.2.2" - stringset "~0.2.1" - tryor "~0.1.2" - yargs "~3.27.0" - -degenerator@~1.0.0: +degenerator@~1.0.2: version "1.0.4" resolved "https://registry.yarnpkg.com/degenerator/-/degenerator-1.0.4.tgz#fcf490a37ece266464d9cc431ab98c5819ced095" dependencies: @@ -2008,7 +2059,7 @@ degenerator@~1.0.0: escodegen "1.x.x" esprima "3.x.x" -del@^2.2.0: +del@^2.0.2, del@^2.2.0: version "2.2.2" resolved "https://registry.yarnpkg.com/del/-/del-2.2.2.tgz#c12c981d067846c84bcaf862cff930d907ffd1a8" dependencies: @@ -2044,6 +2095,13 @@ deprecated@^0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/deprecated/-/deprecated-0.0.1.tgz#f9c9af5464afa1e7a971458a8bdef2aa94d5bb19" +des.js@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/des.js/-/des.js-1.0.0.tgz#c074d2e2aa6a8a9a07dbd61f9a15c2cd83ec8ecc" + dependencies: + inherits "^2.0.1" + minimalistic-assert "^1.0.0" + destroy@~1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80" @@ -2054,26 +2112,15 @@ detect-file@^0.1.0: dependencies: fs-exists-sync "^0.1.0" -detect-indent@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/detect-indent/-/detect-indent-3.0.1.tgz#9dc5e5ddbceef8325764b9451b02bc6d54084f75" - dependencies: - get-stdin "^4.0.1" - minimist "^1.1.0" - repeating "^1.1.0" - detect-indent@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/detect-indent/-/detect-indent-4.0.0.tgz#f76d064352cdf43a1cb6ce619c4ee3a9475de208" dependencies: repeating "^2.0.0" -detective@^4.3.1: - version "4.5.0" - resolved "https://registry.yarnpkg.com/detective/-/detective-4.5.0.tgz#6e5a8c6b26e6c7a254b1c6b6d7490d98ec91edd1" - dependencies: - acorn "^4.0.3" - defined "^1.0.0" +detect-newline@2.X: + version "2.1.0" + resolved "https://registry.yarnpkg.com/detect-newline/-/detect-newline-2.1.0.tgz#f41f1c10be4b00e87b5f13da680759f2c5bfd3e2" di@^0.0.1: version "0.0.1" @@ -2087,6 +2134,14 @@ diff@1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/diff/-/diff-1.4.0.tgz#7f28d2eb9ee7b15a97efd89ce63dcfdaa3ccbabf" +diffie-hellman@^5.0.0: + version "5.0.2" + resolved "https://registry.yarnpkg.com/diffie-hellman/-/diffie-hellman-5.0.2.tgz#b5835739270cfe26acf632099fded2a07f209e5e" + dependencies: + bn.js "^4.1.0" + miller-rabin "^4.0.0" + randombytes "^2.0.0" + dmd@^1.4.1: version "1.4.2" resolved "https://registry.yarnpkg.com/dmd/-/dmd-1.4.2.tgz#b1304b98a5700a6bfe5dcf91be657c981700a4bc" @@ -2108,6 +2163,20 @@ dmd@^1.4.1: string-tools "^1.0.0" walk-back "^2.0.1" +doctrine@1.5.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-1.5.0.tgz#379dce730f6166f76cefa4e6707a159b02c5a6fa" + dependencies: + esutils "^2.0.2" + isarray "^1.0.0" + +doctrine@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-2.0.0.tgz#c73d8d2909d22291e1a007a395804da8b665fe63" + dependencies: + esutils "^2.0.2" + isarray "^1.0.0" + dom-serialize@^2.2.0: version "2.2.1" resolved "https://registry.yarnpkg.com/dom-serialize/-/dom-serialize-2.2.1.tgz#562ae8999f44be5ea3076f5419dcd59eb43ac95b" @@ -2117,38 +2186,10 @@ dom-serialize@^2.2.0: extend "^3.0.0" void-elements "^2.0.0" -dom-serializer@0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-0.1.0.tgz#073c697546ce0780ce23be4a28e293e40bc30c82" - dependencies: - domelementtype "~1.1.1" - entities "~1.1.1" - domain-browser@^1.1.1: version "1.1.7" resolved "https://registry.yarnpkg.com/domain-browser/-/domain-browser-1.1.7.tgz#867aa4b093faa05f1de08c06f4d7b21fdf8698bc" -domelementtype@1: - version "1.3.0" - resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-1.3.0.tgz#b17aed82e8ab59e52dd9c19b1756e0fc187204c2" - -domelementtype@~1.1.1: - version "1.1.3" - resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-1.1.3.tgz#bd28773e2642881aec51544924299c5cd822185b" - -domhandler@2.3: - version "2.3.0" - resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-2.3.0.tgz#2de59a0822d5027fabff6f032c2b25a2a8abe738" - dependencies: - domelementtype "1" - -domutils@1.5: - version "1.5.1" - resolved "https://registry.yarnpkg.com/domutils/-/domutils-1.5.1.tgz#dcd8488a26f563d61079e48c9f7b7e32373682cf" - dependencies: - dom-serializer "0" - domelementtype "1" - duplexer2@0.0.2: version "0.0.2" resolved "https://registry.yarnpkg.com/duplexer2/-/duplexer2-0.0.2.tgz#c614dcf67e2fb14995a91711e5a617e8a60a31db" @@ -2159,6 +2200,15 @@ duplexer@~0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/duplexer/-/duplexer-0.1.1.tgz#ace6ff808c1ce66b57d1ebf97977acb02334cfc1" +duplexify@^3.5.0: + version "3.5.0" + resolved "https://registry.yarnpkg.com/duplexify/-/duplexify-3.5.0.tgz#1aa773002e1578457e9d9d4a50b0ccaaebcbd604" + dependencies: + end-of-stream "1.0.0" + inherits "^2.0.1" + readable-stream "^2.0.0" + stream-shift "^1.0.0" + ecc-jsbn@~0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz#0fc73a9ed5f0d53c38193398523ef7e543777505" @@ -2177,6 +2227,18 @@ ejs@^2.3.1, ejs@^2.5.1: version "2.5.6" resolved "https://registry.yarnpkg.com/ejs/-/ejs-2.5.6.tgz#479636bfa3fe3b1debd52087f0acb204b4f19c88" +elliptic@^6.0.0: + version "6.4.0" + resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.4.0.tgz#cac9af8762c85836187003c8dfe193e5e2eae5df" + dependencies: + bn.js "^4.4.0" + brorand "^1.0.1" + hash.js "^1.0.0" + hmac-drbg "^1.0.0" + inherits "^2.0.1" + minimalistic-assert "^1.0.0" + minimalistic-crypto-utils "^1.0.0" + emojis-list@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-2.1.0.tgz#4daa4d9db00f9819880c79fa457ae5b09a1fd389" @@ -2185,11 +2247,11 @@ encodeurl@~1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.1.tgz#79e3d58655346909fe6f0f45a5de68103b294d20" -end-of-stream@^1.0.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.0.tgz#7a90d833efda6cfa6eac0f4949dbb0fad3a63206" +end-of-stream@1.0.0, end-of-stream@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.0.0.tgz#d4596e702734a93e40e9af864319eabd99ff2f0e" dependencies: - once "^1.4.0" + once "~1.3.0" end-of-stream@~0.1.5: version "0.1.5" @@ -2236,6 +2298,15 @@ engine.io@1.8.3: engine.io-parser "1.3.2" ws "1.1.2" +enhanced-resolve@^3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-3.3.0.tgz#950964ecc7f0332a42321b673b38dc8ff15535b3" + dependencies: + graceful-fs "^4.1.2" + memory-fs "^0.4.0" + object-assign "^4.0.1" + tapable "^0.2.5" + enhanced-resolve@~0.9.0: version "0.9.1" resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-0.9.1.tgz#4d6e689b3725f86090927ccc86cd9f1635b89e2e" @@ -2248,14 +2319,6 @@ ent@~2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/ent/-/ent-2.2.0.tgz#e964219325a21d05f44466a2f686ed6ce5f5dd1d" -entities@1.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/entities/-/entities-1.0.0.tgz#b2987aa3821347fcde642b24fdfc9e4fb712bf26" - -entities@~1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/entities/-/entities-1.1.1.tgz#6e5c2d0a5621b5dadaecef80b90edfb5cd7772f0" - errno@^0.1.3: version "0.1.4" resolved "https://registry.yarnpkg.com/errno/-/errno-0.1.4.tgz#b896e23a9e5e8ba33871fc996abd3635fc9a1c7d" @@ -2275,9 +2338,9 @@ errorhandler@~1.4.2: accepts "~1.3.0" escape-html "~1.0.3" -es5-ext@^0.10.14, es5-ext@^0.10.9, es5-ext@~0.10.14: - version "0.10.15" - resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.15.tgz#c330a5934c1ee21284a7c081a86e5fd937c91ea6" +es5-ext@^0.10.13, es5-ext@^0.10.14, es5-ext@^0.10.9, es5-ext@~0.10.14, es5-ext@~0.10.2: + version "0.10.24" + resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.24.tgz#a55877c9924bc0c8d9bd3c2cbe17495ac1709b14" dependencies: es6-iterator "2" es6-symbol "~3.1" @@ -2339,26 +2402,26 @@ escape-html@~1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" -escape-string-regexp@1.0.2, escape-string-regexp@^1.0.2: +escape-string-regexp@1.0.2, escape-string-regexp@^1.0.0, escape-string-regexp@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.2.tgz#4dbc2fe674e71949caf3fb2695ce7f2dc1d9a8d1" -escape-string-regexp@1.0.5, escape-string-regexp@^1.0.0, escape-string-regexp@^1.0.5, escape-string-regexp@~1.0.5: +escape-string-regexp@1.0.5, escape-string-regexp@^1.0.5, escape-string-regexp@~1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" -escodegen@1.7.x, escodegen@1.x.x: - version "1.7.1" - resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-1.7.1.tgz#30ecfcf66ca98dc67cd2fd162abeb6eafa8ce6fc" +escodegen@1.8.x, escodegen@1.x.x: + version "1.8.1" + resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-1.8.1.tgz#5a5b53af4693110bebb0867aa3430dd3b70a1018" dependencies: - esprima "^1.2.2" + esprima "^2.7.1" estraverse "^1.9.1" esutils "^2.0.2" - optionator "^0.5.0" + optionator "^0.8.1" optionalDependencies: source-map "~0.2.0" -escope@^3.2.0: +escope@^3.6.0: version "3.6.0" resolved "https://registry.yarnpkg.com/escope/-/escope-3.6.0.tgz#e01975e812781a163a6dadfdd80398dc64c889c3" dependencies: @@ -2367,6 +2430,108 @@ escope@^3.2.0: esrecurse "^4.1.0" estraverse "^4.1.1" +eslint-config-standard@^10.2.1: + version "10.2.1" + resolved "https://registry.yarnpkg.com/eslint-config-standard/-/eslint-config-standard-10.2.1.tgz#c061e4d066f379dc17cd562c64e819b4dd454591" + +eslint-import-resolver-node@^0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.1.tgz#4422574cde66a9a7b099938ee4d508a199e0e3cc" + dependencies: + debug "^2.6.8" + resolve "^1.2.0" + +eslint-module-utils@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.1.1.tgz#abaec824177613b8a95b299639e1b6facf473449" + dependencies: + debug "^2.6.8" + pkg-dir "^1.0.0" + +eslint-plugin-import@^2.2.0: + version "2.7.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.7.0.tgz#21de33380b9efb55f5ef6d2e210ec0e07e7fa69f" + dependencies: + builtin-modules "^1.1.1" + contains-path "^0.1.0" + debug "^2.6.8" + doctrine "1.5.0" + eslint-import-resolver-node "^0.3.1" + eslint-module-utils "^2.1.1" + has "^1.0.1" + lodash.cond "^4.3.0" + minimatch "^3.0.3" + read-pkg-up "^2.0.0" + +eslint-plugin-node@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-node/-/eslint-plugin-node-5.1.0.tgz#bc8cdb85180d0b4d946a2531640e2a4dd7a4e6d4" + dependencies: + ignore "^3.3.3" + minimatch "^3.0.4" + resolve "^1.3.3" + semver "5.3.0" + +eslint-plugin-promise@^3.5.0: + version "3.5.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-promise/-/eslint-plugin-promise-3.5.0.tgz#78fbb6ffe047201627569e85a6c5373af2a68fca" + +eslint-plugin-standard@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/eslint-plugin-standard/-/eslint-plugin-standard-3.0.1.tgz#34d0c915b45edc6f010393c7eef3823b08565cf2" + +eslint-scope@^3.7.1: + version "3.7.1" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-3.7.1.tgz#3d63c3edfda02e06e01a452ad88caacc7cdcb6e8" + dependencies: + esrecurse "^4.1.0" + estraverse "^4.1.1" + +eslint@^4.0.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-4.2.0.tgz#a2b3184111b198e02e9c7f3cca625a5e01c56b3d" + dependencies: + ajv "^5.2.0" + babel-code-frame "^6.22.0" + chalk "^1.1.3" + concat-stream "^1.6.0" + debug "^2.6.8" + doctrine "^2.0.0" + eslint-scope "^3.7.1" + espree "^3.4.3" + esquery "^1.0.0" + estraverse "^4.2.0" + esutils "^2.0.2" + file-entry-cache "^2.0.0" + glob "^7.1.2" + globals "^9.17.0" + ignore "^3.3.3" + imurmurhash "^0.1.4" + inquirer "^3.0.6" + is-resolvable "^1.0.0" + js-yaml "^3.8.4" + json-stable-stringify "^1.0.1" + levn "^0.3.0" + lodash "^4.17.4" + minimatch "^3.0.2" + mkdirp "^0.5.1" + natural-compare "^1.4.0" + optionator "^0.8.2" + path-is-inside "^1.0.2" + pluralize "^4.0.0" + progress "^2.0.0" + require-uncached "^1.0.3" + strip-json-comments "~2.0.1" + table "^4.0.1" + text-table "~0.2.0" + +espree@^3.4.3: + version "3.4.3" + resolved "https://registry.yarnpkg.com/espree/-/espree-3.4.3.tgz#2910b5ccd49ce893c2ffffaab4fd8b3a31b82374" + dependencies: + acorn "^5.0.1" + acorn-jsx "^3.0.0" + espree@~3.1.7: version "3.1.7" resolved "https://registry.yarnpkg.com/espree/-/espree-3.1.7.tgz#fd5deec76a97a5120a9cd3a7cb1177a0923b11d2" @@ -2374,54 +2539,44 @@ espree@~3.1.7: acorn "^3.3.0" acorn-jsx "^3.0.0" -esprima-fb@~15001.1001.0-dev-harmony-fb: - version "15001.1001.0-dev-harmony-fb" - resolved "https://registry.yarnpkg.com/esprima-fb/-/esprima-fb-15001.1001.0-dev-harmony-fb.tgz#43beb57ec26e8cf237d3dd8b33e42533577f2659" - -esprima@1.2.x, esprima@^1.2.2: - version "1.2.5" - resolved "https://registry.yarnpkg.com/esprima/-/esprima-1.2.5.tgz#0993502feaf668138325756f30f9a51feeec11e9" - -esprima@2.5.x: - version "2.5.0" - resolved "https://registry.yarnpkg.com/esprima/-/esprima-2.5.0.tgz#f387a46fd344c1b1a39baf8c20bfb43b6d0058cc" +esprima@2.7.x, esprima@^2.6.0, esprima@^2.7.1: + version "2.7.3" + resolved "https://registry.yarnpkg.com/esprima/-/esprima-2.7.3.tgz#96e3b70d5779f6ad49cd032673d1c312767ba581" -esprima@3.x.x, esprima@~3.1.0: +esprima@3.x.x: version "3.1.3" resolved "https://registry.yarnpkg.com/esprima/-/esprima-3.1.3.tgz#fdca51cee6133895e3c88d535ce49dbff62a4633" -esprima@^2.6.0, esprima@~2.7.0: - version "2.7.3" - resolved "https://registry.yarnpkg.com/esprima/-/esprima-2.7.3.tgz#96e3b70d5779f6ad49cd032673d1c312767ba581" +esprima@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.0.tgz#4499eddcd1110e0b218bacf2fa7f7f59f55ca804" + +esquery@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.0.0.tgz#cfba8b57d7fba93f17298a8a006a04cda13d80fa" + dependencies: + estraverse "^4.0.0" esrecurse@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.1.0.tgz#4713b6536adf7f2ac4f327d559e7756bff648220" + version "4.2.0" + resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.2.0.tgz#fa9568d98d3823f9a41d91e902dcab9ea6e5b163" dependencies: - estraverse "~4.1.0" + estraverse "^4.1.0" object-assign "^4.0.1" estraverse@^1.9.1: version "1.9.3" resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-1.9.3.tgz#af67f2dc922582415950926091a4005d29c9bb44" -estraverse@^4.1.0, estraverse@^4.1.1: +estraverse@^4.0.0, estraverse@^4.1.0, estraverse@^4.1.1, estraverse@^4.2.0: version "4.2.0" resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.2.0.tgz#0dee3fed31fcd469618ce7342099fc1afa0bdb13" -estraverse@~1.8.0: - version "1.8.0" - resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-1.8.0.tgz#3f1264fb62c8500dbae5e4f73705cd576d6af428" - -estraverse@~4.1.0: - version "4.1.1" - resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.1.1.tgz#f6caca728933a850ef90661d0e17982ba47111a2" - estree-walker@^0.3.0: version "0.3.1" resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-0.3.1.tgz#e6b1a51cf7292524e7237c312e5fe6660c1ce1aa" -esutils@^2.0.0, esutils@^2.0.2: +esutils@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.2.tgz#0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b" @@ -2429,14 +2584,14 @@ etag@~1.7.0: version "1.7.0" resolved "https://registry.yarnpkg.com/etag/-/etag-1.7.0.tgz#03d30b5f67dd6e632d2945d30d6652731a34d5d8" -event-emitter@~0.3.5: +event-emitter@^0.3.4, event-emitter@~0.3.5: version "0.3.5" resolved "https://registry.yarnpkg.com/event-emitter/-/event-emitter-0.3.5.tgz#df8c69eef1647923c7157b9ce83840610b02cc39" dependencies: d "1" es5-ext "~0.10.14" -event-stream@^3.3.2: +event-stream@*, event-stream@^3.3.2: version "3.3.4" resolved "https://registry.yarnpkg.com/event-stream/-/event-stream-3.3.4.tgz#4ab4c9a0f5a54db9338b4c34d86bfce8f4b35571" dependencies: @@ -2448,7 +2603,7 @@ event-stream@^3.3.2: stream-combiner "~0.0.4" through "~2.3.1" -event-stream@~3.0.18, event-stream@~3.0.20: +event-stream@~3.0.18: version "3.0.20" resolved "https://registry.yarnpkg.com/event-stream/-/event-stream-3.0.20.tgz#038bbb2ea9ea90385b26fbc1854d0b539f2abea3" dependencies: @@ -2468,9 +2623,11 @@ events@^1.0.0: version "1.1.1" resolved "https://registry.yarnpkg.com/events/-/events-1.1.1.tgz#9ebdb7635ad099c70dcc4c2a1f5004288e8bd924" -exit@0.1.2, exit@0.1.x, exit@~0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/exit/-/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c" +evp_bytestokey@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/evp_bytestokey/-/evp_bytestokey-1.0.0.tgz#497b66ad9fef65cd7c08a6180824ba1476b66e53" + dependencies: + create-hash "^1.1.1" expand-braces@^0.1.1: version "0.1.2" @@ -2499,12 +2656,18 @@ expand-range@^1.8.1: dependencies: fill-range "^2.1.0" -expand-tilde@^1.2.1, expand-tilde@^1.2.2: +expand-tilde@^1.2.2: version "1.2.2" resolved "https://registry.yarnpkg.com/expand-tilde/-/expand-tilde-1.2.2.tgz#0b81eba897e5a3d31d1c3d102f8f01441e559449" dependencies: os-homedir "^1.0.1" +expand-tilde@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/expand-tilde/-/expand-tilde-2.0.2.tgz#97e801aa052df02454de46b02bf621642cdc8502" + dependencies: + homedir-polyfill "^1.0.1" + expect.js@^0.3.1: version "0.3.1" resolved "https://registry.yarnpkg.com/expect.js/-/expect.js-0.3.1.tgz#b0a59a0d2eff5437544ebf0ceaa6015841d09b5b" @@ -2524,8 +2687,16 @@ express-session@~1.11.3: utils-merge "1.0.0" extend@3, extend@^3.0.0, extend@~3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.0.tgz#5a474353b9f3353ddd8176dfd37b91c83a46f1d4" + version "3.0.1" + resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.1.tgz#a755ea7bc1adfcc5a31ce7e762dbaadc5e636444" + +external-editor@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-2.0.4.tgz#1ed9199da9cbfe2ef2f7a31b2fde8b0d12368972" + dependencies: + iconv-lite "^0.4.17" + jschardet "^1.4.2" + tmp "^0.0.31" extglob@^0.3.1: version "0.3.2" @@ -2533,23 +2704,10 @@ extglob@^0.3.1: dependencies: is-extglob "^1.0.0" -extract-zip@~1.5.0: - version "1.5.0" - resolved "https://registry.yarnpkg.com/extract-zip/-/extract-zip-1.5.0.tgz#92ccf6d81ef70a9fa4c1747114ccef6d8688a6c4" - dependencies: - concat-stream "1.5.0" - debug "0.7.4" - mkdirp "0.5.0" - yauzl "2.4.1" - extsprintf@1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.0.2.tgz#e1080e0658e300b06294990cc70e1502235fd550" -eyes@0.1.x: - version "0.1.8" - resolved "https://registry.yarnpkg.com/eyes/-/eyes-0.1.8.tgz#62cf120234c683785d902348a800ef3e0cc20bc0" - faker@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/faker/-/faker-3.1.0.tgz#0f908faf4e6ec02524e54a57e432c5c013e08c9f" @@ -2561,9 +2719,13 @@ fancy-log@^1.1.0: chalk "^1.1.1" time-stamp "^1.0.0" -fast-levenshtein@~1.0.0: - version "1.0.7" - resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-1.0.7.tgz#0178dcdee023b92905193af0959e8a7639cfdcb9" +fast-deep-equal@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-1.0.0.tgz#96256a3bc975595eb36d82e9929d060d893439ff" + +fast-levenshtein@~2.0.4: + version "2.0.6" + resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" faye-websocket@~0.10.0: version "0.10.0" @@ -2571,12 +2733,6 @@ faye-websocket@~0.10.0: dependencies: websocket-driver ">=0.5.1" -fd-slicer@~1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/fd-slicer/-/fd-slicer-1.0.1.tgz#8b5bcbd9ec327c5041bf9ab023fd6750f1177e65" - dependencies: - pend "~1.2.0" - feature-detect-es6@^1.2.0, feature-detect-es6@^1.3.0, feature-detect-es6@^1.3.1: version "1.3.1" resolved "https://registry.yarnpkg.com/feature-detect-es6/-/feature-detect-es6-1.3.1.tgz#f888736af9cb0c91f55663bfa4762eb96ee7047f" @@ -2590,6 +2746,19 @@ figures@^1.3.5: escape-string-regexp "^1.0.5" object-assign "^4.1.0" +figures@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/figures/-/figures-2.0.0.tgz#3ab1a2d2a62c8bfb431a0c94cb797a2fce27c962" + dependencies: + escape-string-regexp "^1.0.5" + +file-entry-cache@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-2.0.0.tgz#c392990c3e684783d838b8c84a45d8a048458361" + dependencies: + flat-cache "^1.2.1" + object-assign "^4.0.1" + file-loader@^0.8.1: version "0.8.5" resolved "https://registry.yarnpkg.com/file-loader/-/file-loader-0.8.5.tgz#9275d031fe780f27d47f5f4af02bd43713cc151b" @@ -2610,27 +2779,20 @@ file-set@~0.2.1: array-tools "^2" glob "^4" -file-uri-to-path@0: - version "0.0.2" - resolved "https://registry.yarnpkg.com/file-uri-to-path/-/file-uri-to-path-0.0.2.tgz#37cdd1b5b905404b3f05e1b23645be694ff70f82" +file-uri-to-path@1: + version "1.0.0" + resolved "https://registry.yarnpkg.com/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz#553a7b8446ff6f684359c445f1e37a05dacc33dd" filename-regex@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/filename-regex/-/filename-regex-2.0.0.tgz#996e3e80479b98b9897f15a8a58b3d084e926775" - -fileset@0.1.x: - version "0.1.8" - resolved "https://registry.yarnpkg.com/fileset/-/fileset-0.1.8.tgz#506b91a9396eaa7e32fb42a84077c7a0c736b741" - dependencies: - glob "3.x" - minimatch "0.x" + version "2.0.1" + resolved "https://registry.yarnpkg.com/filename-regex/-/filename-regex-2.0.1.tgz#c1c4b9bee3e09725ddb106b75c1e301fe2f18b26" -fileset@0.2.x: - version "0.2.1" - resolved "https://registry.yarnpkg.com/fileset/-/fileset-0.2.1.tgz#588ef8973c6623b2a76df465105696b96aac8067" +fileset@^2.0.2: + version "2.0.3" + resolved "https://registry.yarnpkg.com/fileset/-/fileset-2.0.3.tgz#8e7548a96d3cc2327ee5e674168723a333bba2a0" dependencies: - glob "5.x" - minimatch "2.x" + glob "^7.0.3" + minimatch "^3.0.3" fill-keys@^1.0.2: version "1.0.2" @@ -2664,11 +2826,11 @@ finalhandler@0.4.0: on-finished "~2.3.0" unpipe "~1.0.0" -finalhandler@1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.0.0.tgz#b5691c2c0912092f18ac23e9416bde5cd7dc6755" +finalhandler@1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.0.3.tgz#ef47e77950e999780e86022a560e3217e0d0cc89" dependencies: - debug "2.6.1" + debug "2.6.7" encodeurl "~1.0.1" escape-html "~1.0.3" on-finished "~2.3.0" @@ -2676,13 +2838,13 @@ finalhandler@1.0.0: statuses "~1.3.1" unpipe "~1.0.0" -find-cache-dir@^0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-0.1.1.tgz#c8defae57c8a52a8a784f9e31c57c742e993a0b9" +find-cache-dir@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-1.0.0.tgz#9288e3e9e3cc3748717d39eade17cf71fc30ee6f" dependencies: commondir "^1.0.1" - mkdirp "^0.5.1" - pkg-dir "^1.0.0" + make-dir "^1.0.0" + pkg-dir "^2.0.0" find-index@^0.1.1: version "0.1.1" @@ -2702,6 +2864,12 @@ find-up@^1.0.0: path-exists "^2.0.0" pinkie-promise "^2.0.0" +find-up@^2.0.0, find-up@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-2.1.0.tgz#45d1b7e506c717ddd482775a2b77920a3c0c57a7" + dependencies: + locate-path "^2.0.0" + findup-sync@^0.4.2: version "0.4.3" resolved "https://registry.yarnpkg.com/findup-sync/-/findup-sync-0.4.3.tgz#40043929e7bc60adf0b7f4827c4c6e75a0deca12" @@ -2712,15 +2880,13 @@ findup-sync@^0.4.2: resolve-dir "^0.1.0" fined@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/fined/-/fined-1.0.2.tgz#5b28424b760d7598960b7ef8480dff8ad3660e97" + version "1.1.0" + resolved "https://registry.yarnpkg.com/fined/-/fined-1.1.0.tgz#b37dc844b76a2f5e7081e884f7c0ae344f153476" dependencies: - expand-tilde "^1.2.1" - lodash.assignwith "^4.0.7" - lodash.isempty "^4.2.1" - lodash.isplainobject "^4.0.4" - lodash.isstring "^4.0.1" - lodash.pick "^4.2.1" + expand-tilde "^2.0.2" + is-plain-object "^2.0.3" + object.defaults "^1.1.0" + object.pick "^1.2.0" parse-filepath "^1.0.1" first-chunk-stream@^1.0.0: @@ -2731,6 +2897,15 @@ flagged-respawn@^0.3.2: version "0.3.2" resolved "https://registry.yarnpkg.com/flagged-respawn/-/flagged-respawn-0.3.2.tgz#ff191eddcd7088a675b2610fffc976be9b8074b5" +flat-cache@^1.2.1: + version "1.2.2" + resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-1.2.2.tgz#fa86714e72c21db88601761ecf2f555d1abc6b96" + dependencies: + circular-json "^0.3.1" + del "^2.0.2" + graceful-fs "^4.1.2" + write "^0.2.1" + for-in@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" @@ -2741,6 +2916,12 @@ for-own@^0.1.4: dependencies: for-in "^1.0.1" +for-own@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/for-own/-/for-own-1.0.0.tgz#c63332f415cedc4b04dbfe70cf836494c53cb44b" + dependencies: + for-in "^1.0.1" + foreachasync@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/foreachasync/-/foreachasync-3.0.0.tgz#5502987dc8714be3392097f32e0071c9dee07cf6" @@ -2749,10 +2930,14 @@ forever-agent@~0.5.0: version "0.5.2" resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.5.2.tgz#6d0e09c4921f94a27f63d3b49c5feff1ea4c5130" -forever-agent@~0.6.0, forever-agent@~0.6.1: +forever-agent@~0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" +fork-stream@^0.0.4: + version "0.0.4" + resolved "https://registry.yarnpkg.com/fork-stream/-/fork-stream-0.0.4.tgz#db849fce77f6708a5f8f386ae533a0907b54ae70" + form-data@~0.1.0: version "0.1.4" resolved "https://registry.yarnpkg.com/form-data/-/form-data-0.1.4.tgz#91abd788aba9702b1aabfa8bc01031a2ac9e3b12" @@ -2761,25 +2946,9 @@ form-data@~0.1.0: combined-stream "~0.0.4" mime "~1.2.11" -form-data@~0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/form-data/-/form-data-0.2.0.tgz#26f8bc26da6440e299cbdcfb69035c4f77a6e466" - dependencies: - async "~0.9.0" - combined-stream "~0.0.4" - mime-types "~2.0.3" - -form-data@~1.0.0-rc3: - version "1.0.1" - resolved "https://registry.yarnpkg.com/form-data/-/form-data-1.0.1.tgz#ae315db9a4907fa065502304a66d7733475ee37c" - dependencies: - async "^2.0.1" - combined-stream "^1.0.5" - mime-types "^2.1.11" - form-data@~2.1.1: - version "2.1.2" - resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.1.2.tgz#89c3534008b97eada4cbb157d58f6f5df025eae4" + version "2.1.4" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.1.4.tgz#33c183acf193276ecaa98143a69e94bfee1750d1" dependencies: asynckit "^0.4.0" combined-stream "^1.0.5" @@ -2809,16 +2978,6 @@ fs-exists-sync@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/fs-exists-sync/-/fs-exists-sync-0.1.0.tgz#982d6893af918e72d08dec9e8673ff2b5a8d6add" -fs-extra@~0.26.4: - version "0.26.7" - resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-0.26.7.tgz#9ae1fdd94897798edab76d0918cf42d0c3184fa9" - dependencies: - graceful-fs "^4.1.2" - jsonfile "^2.1.0" - klaw "^1.0.0" - path-is-absolute "^1.0.0" - rimraf "^2.2.8" - fs-extra@~0.6.1: version "0.6.4" resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-0.6.4.tgz#f46f0c75b7841f8d200b3348cd4d691d5a099d15" @@ -2828,10 +2987,6 @@ fs-extra@~0.6.1: ncp "~0.4.2" rimraf "~2.2.0" -fs-readdir-recursive@^0.1.0: - version "0.1.2" - resolved "https://registry.yarnpkg.com/fs-readdir-recursive/-/fs-readdir-recursive-0.1.2.tgz#315b4fb8c1ca5b8c47defef319d073dad3568059" - fs-then-native@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/fs-then-native/-/fs-then-native-1.0.2.tgz#ac8d3807c9f1bbd1279607fb228e0ab649bb41fe" @@ -2851,11 +3006,11 @@ fs.realpath@^1.0.0: resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" fsevents@^1.0.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.1.1.tgz#f19fd28f43eeaf761680e519a203c4d0b3d31aff" + version "1.1.2" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.1.2.tgz#3282b713fb3ad80ede0e9fcf4611b5aa6fc033f4" dependencies: nan "^2.3.0" - node-pre-gyp "^0.6.29" + node-pre-gyp "^0.6.36" fstream-ignore@^1.0.5: version "1.0.5" @@ -2883,16 +3038,20 @@ fstream@^1.0.0, fstream@^1.0.10, fstream@^1.0.2: mkdirp ">=0.5 0" rimraf "2" -ftp@~0.3.5: +ftp@~0.3.10: version "0.3.10" resolved "https://registry.yarnpkg.com/ftp/-/ftp-0.3.10.tgz#9197d861ad8142f3e63d5a83bfe4c59f7330885d" dependencies: readable-stream "1.1.x" xregexp "2.0.0" -gauge@~2.7.1: - version "2.7.3" - resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.3.tgz#1c23855f962f17b3ad3d0dc7443f304542edfe09" +function-bind@^1.0.2: + version "1.1.0" + resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.0.tgz#16176714c801798e4e8f2cf7f7529467bb4a5771" + +gauge@~2.7.3: + version "2.7.4" + resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7" dependencies: aproba "^1.0.3" console-control-strings "^1.0.0" @@ -2927,20 +3086,20 @@ get-stdin@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-4.0.1.tgz#b968c6b0a04384324902e8bf1a5df32579a450fe" -get-uri@1: - version "1.1.0" - resolved "https://registry.yarnpkg.com/get-uri/-/get-uri-1.1.0.tgz#7375d04daf7fcb584b3632679cbdf339b51bb149" +get-uri@2: + version "2.0.1" + resolved "https://registry.yarnpkg.com/get-uri/-/get-uri-2.0.1.tgz#dbdcacacd8c608a38316869368117697a1631c59" dependencies: - data-uri-to-buffer "0" + data-uri-to-buffer "1" debug "2" extend "3" - file-uri-to-path "0" - ftp "~0.3.5" + file-uri-to-path "1" + ftp "~0.3.10" readable-stream "2" getpass@^0.1.1: - version "0.1.6" - resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.6.tgz#283ffd9fc1256840875311c1b60e8c40187110e6" + version "0.1.7" + resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa" dependencies: assert-plus "^1.0.0" @@ -2980,13 +3139,6 @@ glob2base@^0.0.12: dependencies: find-index "^0.1.1" -glob@3.2.11, glob@3.x: - version "3.2.11" - resolved "https://registry.yarnpkg.com/glob/-/glob-3.2.11.tgz#4a973f635b9190f715d10987d5c00fd2815ebe3d" - dependencies: - inherits "2" - minimatch "0.3" - glob@3.2.3: version "3.2.3" resolved "https://registry.yarnpkg.com/glob/-/glob-3.2.3.tgz#e313eeb249c7affaa5c475286b0e115b59839467" @@ -2995,16 +3147,6 @@ glob@3.2.3: inherits "2" minimatch "~0.2.11" -glob@5.x, glob@^5.0.1, glob@^5.0.10, glob@^5.0.15: - version "5.0.15" - resolved "https://registry.yarnpkg.com/glob/-/glob-5.0.15.tgz#1bc936b9e02f4a603fcc222ecf7633d30b8b93b1" - dependencies: - inflight "^1.0.4" - inherits "2" - minimatch "2 || 3" - once "^1.3.0" - path-is-absolute "^1.0.0" - glob@7.0.5: version "7.0.5" resolved "https://registry.yarnpkg.com/glob/-/glob-7.0.5.tgz#b4202a69099bbb4d292a7c1b95b6682b67ebdc95" @@ -3025,14 +3167,24 @@ glob@^4, glob@^4.3.1: minimatch "^2.0.1" once "^1.3.0" -glob@^7.0.0, glob@^7.0.3, glob@^7.0.5, glob@^7.1.0, glob@^7.1.1: - version "7.1.1" - resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.1.tgz#805211df04faaf1c63a3600306cdf5ade50b2ec8" +glob@^5.0.10, glob@^5.0.14, glob@^5.0.15: + version "5.0.15" + resolved "https://registry.yarnpkg.com/glob/-/glob-5.0.15.tgz#1bc936b9e02f4a603fcc222ecf7633d30b8b93b1" + dependencies: + inflight "^1.0.4" + inherits "2" + minimatch "2 || 3" + once "^1.3.0" + path-is-absolute "^1.0.0" + +glob@^7.0.0, glob@^7.0.3, glob@^7.0.5, glob@^7.1.0, glob@^7.1.1, glob@^7.1.2: + version "7.1.2" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.2.tgz#c19c9df9a028702d678612384a6552404c636d15" dependencies: fs.realpath "^1.0.0" inflight "^1.0.4" inherits "2" - minimatch "^3.0.2" + minimatch "^3.0.4" once "^1.3.0" path-is-absolute "^1.0.0" @@ -3069,13 +3221,9 @@ global-prefix@^0.1.4: is-windows "^0.2.0" which "^1.2.12" -globals@^6.4.0: - version "6.4.1" - resolved "https://registry.yarnpkg.com/globals/-/globals-6.4.1.tgz#8498032b3b6d1cc81eebc5f79690d8fe29fabf4f" - -globals@^9.0.0: - version "9.17.0" - resolved "https://registry.yarnpkg.com/globals/-/globals-9.17.0.tgz#0c0ca696d9b9bb694d2e5470bd37777caad50286" +globals@^9.0.0, globals@^9.17.0: + version "9.18.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-9.18.0.tgz#aa3896b3e69b487f17e31ed2143d69a8e30c2d8a" globby@^5.0.0: version "5.0.0" @@ -3102,16 +3250,16 @@ glogg@^1.0.0: dependencies: sparkles "^1.0.0" +graceful-fs@4.X, graceful-fs@^4.1.0, graceful-fs@^4.1.2, graceful-fs@^4.1.9: + version "4.1.11" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658" + graceful-fs@^3.0.0, graceful-fs@~3.0.2: version "3.0.11" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-3.0.11.tgz#7613c778a1afea62f25c630a086d7f3acbbdd818" dependencies: natives "^1.1.0" -graceful-fs@^4.1.2, graceful-fs@^4.1.4, graceful-fs@^4.1.6, graceful-fs@^4.1.9: - version "4.1.11" - resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658" - graceful-fs@~1.2.0: version "1.2.3" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-1.2.3.tgz#15a4806a57547cb2d2dbf27f42e89a8c3451b364" @@ -3143,7 +3291,7 @@ gulp-babel@^6.1.2: through2 "^2.0.0" vinyl-sourcemaps-apply "^0.2.0" -gulp-clean@^0.3.1: +gulp-clean@^0.3.2: version "0.3.2" resolved "https://registry.yarnpkg.com/gulp-clean/-/gulp-clean-0.3.2.tgz#a347d473acea40182f935587a451941671928102" dependencies: @@ -3159,9 +3307,9 @@ gulp-concat@^2.6.0: through2 "^2.0.0" vinyl "^2.0.0" -gulp-connect@^2.0.6: - version "2.3.1" - resolved "https://registry.yarnpkg.com/gulp-connect/-/gulp-connect-2.3.1.tgz#14ae7173328b691252b01fc1930a39cbb24fb33c" +gulp-connect@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/gulp-connect/-/gulp-connect-5.0.0.tgz#f2fdf306ae911468368c2285f2d782f13eddaf4e" dependencies: connect "^2.30.0" connect-livereload "^0.5.4" @@ -3169,6 +3317,21 @@ gulp-connect@^2.0.6: gulp-util "^3.0.6" tiny-lr "^0.2.1" +gulp-eslint@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/gulp-eslint/-/gulp-eslint-4.0.0.tgz#16d9ea4d696e7b7a9d65eeb1aa5bc4ba0a22c7f7" + dependencies: + eslint "^4.0.0" + gulp-util "^3.0.8" + +gulp-footer@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/gulp-footer/-/gulp-footer-1.0.5.tgz#e84ca777e266be7bbc2d45d2df0e7eba8dfa3e54" + dependencies: + event-stream "*" + gulp-util "*" + lodash.assign "*" + gulp-header@^1.7.1: version "1.8.8" resolved "https://registry.yarnpkg.com/gulp-header/-/gulp-header-1.8.8.tgz#4509c64677aab56b5ee8e4669a79b1655933a49e" @@ -3178,14 +3341,13 @@ gulp-header@^1.7.1: object-assign "*" through2 "^2.0.0" -gulp-jscs@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/gulp-jscs/-/gulp-jscs-3.0.2.tgz#dc7fbb01ce2bfc8325bba7cbbf95d65e43530478" +gulp-if@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/gulp-if/-/gulp-if-2.0.2.tgz#a497b7e7573005041caa2bc8b7dda3c80444d629" dependencies: - gulp-util "^3.0.4" - jscs "^2.1.1" - through2 "^2.0.0" - tildify "^1.0.0" + gulp-match "^1.0.3" + ternary-stream "^2.0.1" + through2 "^2.0.1" gulp-jsdoc-to-markdown@^1.2.1: version "1.2.2" @@ -3195,36 +3357,11 @@ gulp-jsdoc-to-markdown@^1.2.1: jsdoc-to-markdown "^1.3.4" through2 "^2.0.1" -gulp-jshint@^1.8.4: - version "1.12.0" - resolved "https://registry.yarnpkg.com/gulp-jshint/-/gulp-jshint-1.12.0.tgz#23fbd1bafdd6fbfe61ea64667a74809a961d03de" - dependencies: - gulp-util "^3.0.0" - jshint "^2.7.0" - lodash "^3.0.1" - minimatch "^2.0.1" - rcloader "0.1.2" - through2 "~0.6.1" - -gulp-karma@0.0.4: - version "0.0.4" - resolved "https://registry.yarnpkg.com/gulp-karma/-/gulp-karma-0.0.4.tgz#65cc202483f25369966ed60ff5dba1f6476131bd" - dependencies: - event-stream "~3.0.20" - gulp-util "~2.2.14" - optimist "~0.6.0" - xtend "~2.1.1" - -gulp-mocha@^2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/gulp-mocha/-/gulp-mocha-2.2.0.tgz#1ce5eba4b94b40c7436afec3c4982c8eea894192" +gulp-match@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/gulp-match/-/gulp-match-1.0.3.tgz#91c7c0d7f29becd6606d57d80a7f8776a87aba8e" dependencies: - gulp-util "^3.0.0" - mocha "^2.0.1" - plur "^2.1.0" - resolve-from "^1.0.0" - temp "^0.8.3" - through "^2.3.4" + minimatch "^3.0.3" gulp-optimize-js@^1.1.0: version "1.1.0" @@ -3256,16 +3393,36 @@ gulp-shell@^0.5.2: lodash "^4.0.0" through2 "^2.0.0" -gulp-uglify@^0.3.1: - version "0.3.2" - resolved "https://registry.yarnpkg.com/gulp-uglify/-/gulp-uglify-0.3.2.tgz#fa37bf6d4ad9a29a349c6cba862abb22eba67aac" +gulp-sourcemaps@^2.6.0: + version "2.6.0" + resolved "https://registry.yarnpkg.com/gulp-sourcemaps/-/gulp-sourcemaps-2.6.0.tgz#7ccce899a8a3bfca1593a3348d0fbf41dd3f51e5" + dependencies: + "@gulp-sourcemaps/identity-map" "1.X" + "@gulp-sourcemaps/map-sources" "1.X" + acorn "4.X" + convert-source-map "1.X" + css "2.X" + debug-fabulous "0.1.X" + detect-newline "2.X" + graceful-fs "4.X" + source-map "0.X" + strip-bom-string "1.X" + through2 "2.X" + vinyl "1.X" + +gulp-uglify@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/gulp-uglify/-/gulp-uglify-3.0.0.tgz#0df0331d72a0d302e3e37e109485dddf33c6d1ca" dependencies: - deepmerge ">=0.2.7 <0.3.0-0" - gulp-util ">=3.0.0 <4.0.0-0" - through2 ">=0.6.1 <1.0.0-0" - uglify-js "2.4.6" + gulplog "^1.0.0" + has-gulplog "^0.1.0" + lodash "^4.13.1" + make-error-cause "^1.1.1" + through2 "^2.0.0" + uglify-js "^3.0.5" + vinyl-sourcemaps-apply "^0.2.0" -gulp-util@*, "gulp-util@>=3.0.0 <4.0.0-0", gulp-util@^3.0.0, gulp-util@^3.0.4, gulp-util@^3.0.6, gulp-util@^3.0.7: +gulp-util@*, gulp-util@^3.0.0, gulp-util@^3.0.4, gulp-util@^3.0.6, gulp-util@^3.0.7, gulp-util@^3.0.8: version "3.0.8" resolved "https://registry.yarnpkg.com/gulp-util/-/gulp-util-3.0.8.tgz#0054e1e744502e27c04c187c3ecc505dd54bbb4f" dependencies: @@ -3288,7 +3445,7 @@ gulp-util@*, "gulp-util@>=3.0.0 <4.0.0-0", gulp-util@^3.0.0, gulp-util@^3.0.4, g through2 "^2.0.0" vinyl "^0.5.0" -gulp-util@^2.2.14, gulp-util@~2.2.14: +gulp-util@^2.2.14: version "2.2.20" resolved "https://registry.yarnpkg.com/gulp-util/-/gulp-util-2.2.20.tgz#d7146e5728910bd8f047a6b0b1e549bc22dbd64c" dependencies: @@ -3311,16 +3468,6 @@ gulp-webdriver@^1.0.1: through2 "^0.6.5" webdriverio "^3.4.0" -gulp-zip@^3.1.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/gulp-zip/-/gulp-zip-3.2.0.tgz#ebd198dae6dc2d5f44d814569c8ec42118a93ef9" - dependencies: - chalk "^1.0.0" - concat-stream "^1.4.7" - gulp-util "^3.0.0" - through2 "^2.0.1" - yazl "^2.1.0" - gulp@^3.8.7: version "3.9.1" resolved "https://registry.yarnpkg.com/gulp/-/gulp-3.9.1.tgz#571ce45928dd40af6514fc4011866016c13845b4" @@ -3381,9 +3528,9 @@ handlebars@^3.0.0, handlebars@^3.0.3: optionalDependencies: uglify-js "~2.3" -handlebars@^4.0.1: - version "4.0.6" - resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.0.6.tgz#2ce4484850537f9c97a8026d5399b935c4ed4ed7" +handlebars@^4.0.1, handlebars@^4.0.3: + version "4.0.10" + resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.0.10.tgz#3d30c718b09a3d96f23ea4cc1f403c4d3ba9ff4f" dependencies: async "^1.4.0" optimist "^0.6.1" @@ -3395,16 +3542,7 @@ har-schema@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-1.0.5.tgz#d263135f43307c02c602afc8fe95970c0151369e" -har-validator@^1.4.0: - version "1.8.0" - resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-1.8.0.tgz#d83842b0eb4c435960aeb108a067a3aa94c0eeb2" - dependencies: - bluebird "^2.9.30" - chalk "^1.0.0" - commander "^2.8.1" - is-my-json-valid "^2.12.0" - -har-validator@~2.0.2, har-validator@~2.0.6: +har-validator@~2.0.6: version "2.0.6" resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-2.0.6.tgz#cdcbc08188265ad119b6a5a7c8ab70eecfb5d27d" dependencies: @@ -3438,10 +3576,6 @@ has-binary@0.1.7: dependencies: isarray "0.0.1" -has-color@~0.1.0: - version "0.1.7" - resolved "https://registry.yarnpkg.com/has-color/-/has-color-0.1.7.tgz#67144a5260c34fc3cca677d041daf52fe7b78b2f" - has-cors@1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/has-cors/-/has-cors-1.1.0.tgz#5e474793f7ea9843d1bb99c23eef49ff126fff39" @@ -3450,6 +3584,10 @@ has-flag@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-1.0.0.tgz#9d9e793165ce017a00f00418c43f942a7b1d11fa" +has-flag@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-2.0.0.tgz#e8207af1cc7b30d446cc70b734b5e8be18f88d51" + has-gulplog@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/has-gulplog/-/has-gulplog-0.1.0.tgz#6414c82913697da51590397dafb12f22967811ce" @@ -3460,12 +3598,24 @@ has-unicode@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" -hasha@^2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/hasha/-/hasha-2.2.0.tgz#78d7cbfc1e6d66303fe79837365984517b2f6ee1" +has@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/has/-/has-1.0.1.tgz#8461733f538b0837c9361e39a9ab9e9704dc2f28" dependencies: - is-stream "^1.0.1" - pinkie-promise "^2.0.0" + function-bind "^1.0.2" + +hash-base@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/hash-base/-/hash-base-2.0.2.tgz#66ea1d856db4e8a5470cadf6fce23ae5244ef2e1" + dependencies: + inherits "^2.0.1" + +hash.js@^1.0.0, hash.js@^1.0.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/hash.js/-/hash.js-1.1.3.tgz#340dedbe6290187151c1ea1d777a3448935df846" + dependencies: + inherits "^2.0.3" + minimalistic-assert "^1.0.0" hawk@1.1.1: version "1.1.1" @@ -3476,16 +3626,7 @@ hawk@1.1.1: hoek "0.9.x" sntp "0.2.x" -hawk@~2.3.0: - version "2.3.1" - resolved "https://registry.yarnpkg.com/hawk/-/hawk-2.3.1.tgz#1e731ce39447fa1d0f6d707f7bceebec0fd1ec1f" - dependencies: - boom "2.x.x" - cryptiles "2.x.x" - hoek "2.x.x" - sntp "1.x.x" - -hawk@~3.1.0, hawk@~3.1.3: +hawk@~3.1.3: version "3.1.3" resolved "https://registry.yarnpkg.com/hawk/-/hawk-3.1.3.tgz#078444bd7c1640b0fe540d2c9b73d59678e8e1c4" dependencies: @@ -3494,6 +3635,14 @@ hawk@~3.1.0, hawk@~3.1.3: hoek "2.x.x" sntp "1.x.x" +hmac-drbg@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1" + dependencies: + hash.js "^1.0.3" + minimalistic-assert "^1.0.0" + minimalistic-crypto-utils "^1.0.1" + hoek@0.9.x: version "0.9.1" resolved "https://registry.yarnpkg.com/hoek/-/hoek-0.9.1.tgz#3d322462badf07716ea7eb85baf88079cddce505" @@ -3502,13 +3651,6 @@ hoek@2.x.x: version "2.16.3" resolved "https://registry.yarnpkg.com/hoek/-/hoek-2.16.3.tgz#20bb7403d3cea398e91dc4710a8ff1b8274a25ed" -home-or-tmp@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/home-or-tmp/-/home-or-tmp-1.0.0.tgz#4b9f1e40800c3e50c6c27f781676afcce71f3985" - dependencies: - os-tmpdir "^1.0.1" - user-home "^1.1.1" - home-or-tmp@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/home-or-tmp/-/home-or-tmp-2.0.0.tgz#e36c3f2d2cae7d746a857e38d18d5f32a7882db8" @@ -3516,29 +3658,19 @@ home-or-tmp@^2.0.0: os-homedir "^1.0.0" os-tmpdir "^1.0.1" -home-path@^1.0.3: +home-path@^1.0.3, home-path@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/home-path/-/home-path-1.0.5.tgz#788b29815b12d53bacf575648476e6f9041d133f" -homedir-polyfill@^1.0.0: +homedir-polyfill@^1.0.0, homedir-polyfill@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/homedir-polyfill/-/homedir-polyfill-1.0.1.tgz#4c2bbc8a758998feebf5ed68580f76d46768b4bc" dependencies: parse-passwd "^1.0.0" hosted-git-info@^2.1.4: - version "2.4.1" - resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.4.1.tgz#4b0445e41c004a8bd1337773a4ff790ca40318c8" - -htmlparser2@3.8.3, htmlparser2@3.8.x: - version "3.8.3" - resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-3.8.3.tgz#996c28b191516a8be86501a7d79757e5c70c1068" - dependencies: - domelementtype "1" - domhandler "2.3" - domutils "1.5" - entities "1.0" - readable-stream "1.1" + version "2.5.0" + resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.5.0.tgz#6d60e34b3abbc8313062c3b798ef8d901a07af3c" http-errors@~1.3.1: version "1.3.1" @@ -3591,7 +3723,7 @@ https-browserify@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-0.0.1.tgz#3f91365cabe60b77ed0ebba24b454e3e09d95a82" -https-proxy-agent@1, https-proxy-agent@1.0.0: +https-proxy-agent@1, https-proxy-agent@1.0.0, https-proxy-agent@^1.0.0, https-proxy-agent@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-1.0.0.tgz#35f7da6c48ce4ddbfa264891ac593ee5ff8671e6" dependencies: @@ -3599,24 +3731,6 @@ https-proxy-agent@1, https-proxy-agent@1.0.0: debug "2" extend "3" -i@0.3.x: - version "0.3.5" - resolved "https://registry.yarnpkg.com/i/-/i-0.3.5.tgz#1d2b854158ec8169113c6cb7f6b6801e99e211d5" - -ibrik@~2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/ibrik/-/ibrik-2.0.0.tgz#89a2434f2a5c82b92166c3d97de3b5636eea2e9c" - dependencies: - coffee-script "~1.8.0" - esprima "1.2.x" - estraverse "~1.8.0" - fileset "0.1.x" - istanbul "~0.3.2" - lodash "~2.4.1" - mkdirp "~0.5.0" - optimist "~0.6.1" - which "~1.0.5" - iconv-lite@0.4.11: version "0.4.11" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.11.tgz#2ecb42fd294744922209a2e7c404dac8793d8ade" @@ -3625,14 +3739,26 @@ iconv-lite@0.4.13: version "0.4.13" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.13.tgz#1f88aba4ab0b1508e8312acc39345f36e992e2f2" -iconv-lite@0.4.15, iconv-lite@^0.4.5: +iconv-lite@0.4.15: version "0.4.15" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.15.tgz#fe265a218ac6a57cfe854927e9d04c19825eddeb" +iconv-lite@^0.4.17: + version "0.4.18" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.18.tgz#23d8656b16aae6742ac29732ea8f0336a4789cf2" + ieee754@^1.1.4: version "1.1.8" resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.8.tgz#be33d40ac10ef1926701f6f08a2d86fbfd1ad3e4" +ignore@^3.3.3: + version "3.3.3" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-3.3.3.tgz#432352e57accd87ab3110e82d3fea0e47812156d" + +imurmurhash@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" + indent-string@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-2.1.0.tgz#8e2d48348742121b4a8218b7a137e9a52049dc80" @@ -3650,15 +3776,11 @@ inflight@^1.0.4: once "^1.3.0" wrappy "1" -inherit@^2.2.2: - version "2.2.6" - resolved "https://registry.yarnpkg.com/inherit/-/inherit-2.2.6.tgz#f1614b06c8544e8128e4229c86347db73ad9788d" - inherits@1: version "1.0.2" resolved "https://registry.yarnpkg.com/inherits/-/inherits-1.0.2.tgz#ca4309dadee6b54cc0b8d247e8d7c7a0975bdc9b" -inherits@2, inherits@2.0.3, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.0, inherits@~2.0.1: +inherits@2, inherits@2.0.3, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.0, inherits@~2.0.1, inherits@~2.0.3: version "2.0.3" resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" @@ -3683,13 +3805,32 @@ inquirer@^0.8.5: rx "^2.4.3" through "^2.3.6" +inquirer@^3.0.6: + version "3.2.0" + resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-3.2.0.tgz#45b44c2160c729d7578c54060b3eed94487bb42b" + dependencies: + ansi-escapes "^2.0.0" + chalk "^2.0.0" + cli-cursor "^2.1.0" + cli-width "^2.0.0" + external-editor "^2.0.4" + figures "^2.0.0" + lodash "^4.3.0" + mute-stream "0.0.7" + run-async "^2.2.0" + rx-lite "^4.0.8" + rx-lite-aggregates "^4.0.8" + string-width "^2.1.0" + strip-ansi "^4.0.0" + through "^2.3.6" + interpret@^0.6.4: version "0.6.6" resolved "https://registry.yarnpkg.com/interpret/-/interpret-0.6.6.tgz#fecd7a18e7ce5ca6abfb953e1f86213a49f1625b" interpret@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.0.2.tgz#f4f623f0bb7122f15f5717c8e254b8161b5c5b2d" + version "1.0.3" + resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.0.3.tgz#cbc35c62eeee73f19ab7b10a801511401afc0f90" invariant@^2.2.0: version "2.2.2" @@ -3701,14 +3842,14 @@ invert-kv@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-1.0.0.tgz#104a8e4aaca6d3d8cd157a8ef8bfab2d7a3ffdb6" +ip@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/ip/-/ip-1.0.1.tgz#c7e356cdea225ae71b36d70f2e71a92ba4e42590" + ip@^1.1.4: version "1.1.5" resolved "https://registry.yarnpkg.com/ip/-/ip-1.1.5.tgz#bdded70114290828c0a039e72ef25f5aaec4354a" -irregular-plurals@^1.0.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/irregular-plurals/-/irregular-plurals-1.2.0.tgz#38f299834ba8c00c30be9c554e137269752ff3ac" - is-absolute@^0.2.3: version "0.2.6" resolved "https://registry.yarnpkg.com/is-absolute/-/is-absolute-0.2.6.tgz#20de69f3db942ef2d87b9c2da36f172235b1b5eb" @@ -3726,7 +3867,7 @@ is-binary-path@^1.0.0: dependencies: binary-extensions "^1.0.0" -is-buffer@^1.0.2: +is-buffer@^1.1.5: version "1.1.5" resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.5.tgz#1f3b26ef613b214b88cbca23cc6c01d87961eecc" @@ -3737,8 +3878,8 @@ is-builtin-module@^1.0.0: builtin-modules "^1.0.0" is-dotfile@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-dotfile/-/is-dotfile-1.0.2.tgz#2c132383f39199f8edc268ca01b9b007d205cc4d" + version "1.0.3" + resolved "https://registry.yarnpkg.com/is-dotfile/-/is-dotfile-1.0.3.tgz#a6a2f32ffd2dfb04f5ca25ecd0f6b83cf798a1e1" is-equal-shallow@^0.1.3: version "0.1.3" @@ -3766,6 +3907,10 @@ is-fullwidth-code-point@^1.0.0: dependencies: number-is-nan "^1.0.0" +is-fullwidth-code-point@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" + is-generator@^1.0.2: version "1.0.3" resolved "https://registry.yarnpkg.com/is-generator/-/is-generator-1.0.3.tgz#c14c21057ed36e328db80347966c693f886389f3" @@ -3776,13 +3921,7 @@ is-glob@^2.0.0, is-glob@^2.0.1: dependencies: is-extglob "^1.0.0" -is-integer@^1.0.4: - version "1.0.6" - resolved "https://registry.yarnpkg.com/is-integer/-/is-integer-1.0.6.tgz#5273819fada880d123e1ac00a938e7172dd8d95e" - dependencies: - is-finite "^1.0.0" - -is-my-json-valid@^2.12.0, is-my-json-valid@^2.12.4: +is-my-json-valid@^2.12.4: version "2.16.0" resolved "https://registry.yarnpkg.com/is-my-json-valid/-/is-my-json-valid-2.16.0.tgz#f079dd9bfdae65ee2038aae8acbc86ab109e3693" dependencies: @@ -3795,12 +3934,18 @@ is-number@^0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/is-number/-/is-number-0.1.1.tgz#69a7af116963d47206ec9bd9b48a14216f1e3806" -is-number@^2.0.2, is-number@^2.1.0: +is-number@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/is-number/-/is-number-2.1.0.tgz#01fcbbb393463a548f2f466cce16dece49db908f" dependencies: kind-of "^3.0.2" +is-number@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-3.0.0.tgz#24fd6201a4782cf50561c810276afc7d12d71195" + dependencies: + kind-of "^3.0.2" + is-object@~1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/is-object/-/is-object-1.0.1.tgz#8952688c5ec2ffd6b03ecc85e769e02903083470" @@ -3821,6 +3966,12 @@ is-path-inside@^1.0.0: dependencies: path-is-inside "^1.0.1" +is-plain-object@^2.0.3: + version "2.0.4" + resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677" + dependencies: + isobject "^3.0.1" + is-posix-bracket@^0.1.0: version "0.1.1" resolved "https://registry.yarnpkg.com/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz#3334dc79774368e92f016e6fbc0a88f5cd6e6bc4" @@ -3829,6 +3980,10 @@ is-primitive@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/is-primitive/-/is-primitive-2.0.0.tgz#207bab91638499c07b2adf240a41a87210034575" +is-promise@^2.1, is-promise@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-promise/-/is-promise-2.1.0.tgz#79a2a9ece7f096e80f36d2b2f3bc16c1ff4bf3fa" + is-property@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/is-property/-/is-property-1.0.2.tgz#57fe1c4e48474edd65b09911f26b1cd4095dda84" @@ -3839,9 +3994,11 @@ is-relative@^0.2.1: dependencies: is-unc-path "^0.1.1" -is-stream@^1.0.1, is-stream@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" +is-resolvable@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-resolvable/-/is-resolvable-1.0.0.tgz#8df57c61ea2e3c501408d100fb013cf8d6e0cc62" + dependencies: + tryit "^1.0.1" is-typedarray@~1.0.0: version "1.0.0" @@ -3877,31 +4034,101 @@ isexe@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" -isobject@^2.0.0: +isobject@^2.0.0, isobject@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89" dependencies: isarray "1.0.0" -isstream@0.1.x, isstream@~0.1.1, isstream@~0.1.2: +isobject@^3.0.0, isobject@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" + +isstream@~0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" -istanbul-instrumenter-loader@^0.1.2: - version "0.1.3" - resolved "https://registry.yarnpkg.com/istanbul-instrumenter-loader/-/istanbul-instrumenter-loader-0.1.3.tgz#71394c509594ed707ef280a7c7145207de7e2a50" +istanbul-api@^1.1.8: + version "1.1.10" + resolved "https://registry.yarnpkg.com/istanbul-api/-/istanbul-api-1.1.10.tgz#f27e5e7125c8de13f6a80661af78f512e5439b2b" + dependencies: + async "^2.1.4" + fileset "^2.0.2" + istanbul-lib-coverage "^1.1.1" + istanbul-lib-hook "^1.0.7" + istanbul-lib-instrument "^1.7.3" + istanbul-lib-report "^1.1.1" + istanbul-lib-source-maps "^1.2.1" + istanbul-reports "^1.1.1" + js-yaml "^3.7.0" + mkdirp "^0.5.1" + once "^1.4.0" + +istanbul-instrumenter-loader@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/istanbul-instrumenter-loader/-/istanbul-instrumenter-loader-2.0.0.tgz#e5492900ab0bba835efa8024cb00be9b3eea2700" + dependencies: + convert-source-map "^1.3.0" + istanbul-lib-instrument "^1.1.3" + loader-utils "^0.2.16" + object-assign "^4.1.0" + +istanbul-lib-coverage@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-1.1.1.tgz#73bfb998885299415c93d38a3e9adf784a77a9da" + +istanbul-lib-hook@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/istanbul-lib-hook/-/istanbul-lib-hook-1.0.7.tgz#dd6607f03076578fe7d6f2a630cf143b49bacddc" + dependencies: + append-transform "^0.4.0" + +istanbul-lib-instrument@^1.1.3, istanbul-lib-instrument@^1.7.3: + version "1.7.3" + resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-1.7.3.tgz#925b239163eabdd68cc4048f52c2fa4f899ecfa7" + dependencies: + babel-generator "^6.18.0" + babel-template "^6.16.0" + babel-traverse "^6.18.0" + babel-types "^6.18.0" + babylon "^6.17.4" + istanbul-lib-coverage "^1.1.1" + semver "^5.3.0" + +istanbul-lib-report@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/istanbul-lib-report/-/istanbul-lib-report-1.1.1.tgz#f0e55f56655ffa34222080b7a0cd4760e1405fc9" + dependencies: + istanbul-lib-coverage "^1.1.1" + mkdirp "^0.5.1" + path-parse "^1.0.5" + supports-color "^3.1.2" + +istanbul-lib-source-maps@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/istanbul-lib-source-maps/-/istanbul-lib-source-maps-1.2.1.tgz#a6fe1acba8ce08eebc638e572e294d267008aa0c" dependencies: - istanbul "0.x.x" + debug "^2.6.3" + istanbul-lib-coverage "^1.1.1" + mkdirp "^0.5.1" + rimraf "^2.6.1" + source-map "^0.5.3" -istanbul@0.x.x, istanbul@^0.3.2, istanbul@~0.3.0, istanbul@~0.3.2: - version "0.3.22" - resolved "https://registry.yarnpkg.com/istanbul/-/istanbul-0.3.22.tgz#3e164d85021fe19c985d1f0e7ef0c3e22d012eb6" +istanbul-reports@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-1.1.1.tgz#042be5c89e175bc3f86523caab29c014e77fee4e" + dependencies: + handlebars "^4.0.3" + +istanbul@^0.4.5: + version "0.4.5" + resolved "https://registry.yarnpkg.com/istanbul/-/istanbul-0.4.5.tgz#65c7d73d4c4da84d4f3ac310b918fb0b8033733b" dependencies: abbrev "1.0.x" async "1.x" - escodegen "1.7.x" - esprima "2.5.x" - fileset "0.2.x" + escodegen "1.8.x" + esprima "2.7.x" + glob "^5.0.15" handlebars "^4.0.1" js-yaml "3.x" mkdirp "0.5.x" @@ -3926,19 +4153,9 @@ jade@0.26.3: commander "0.6.1" mkdirp "0.3.0" -jodid25519@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/jodid25519/-/jodid25519-1.0.2.tgz#06d4912255093419477d425633606e0e90782967" - dependencies: - jsbn "~0.1.0" - -js-tokens@1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-1.0.1.tgz#cc435a5c8b94ad15acb7983140fc80182c89aeae" - js-tokens@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.1.tgz#08e9f132484a2c45a30907e9dc4d5567b7f114d7" + version "3.0.2" + resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.2.tgz#9866df395102130e38f7f996bceb65443209c25b" js-yaml@3.6.1, js-yaml@3.x: version "3.6.1" @@ -3947,13 +4164,12 @@ js-yaml@3.6.1, js-yaml@3.x: argparse "^1.0.7" esprima "^2.6.0" -js-yaml@~3.4.0: - version "3.4.6" - resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.4.6.tgz#6be1b23f6249f53d293370fd4d1aaa63ce1b4eb0" +js-yaml@^3.7.0, js-yaml@^3.8.4: + version "3.9.0" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.9.0.tgz#4ffbbf25c2ac963b8299dc74da7e3740de1c18ce" dependencies: - argparse "^1.0.2" - esprima "^2.6.0" - inherit "^2.2.2" + argparse "^1.0.7" + esprima "^4.0.0" js2xmlparser@~1.0.0: version "1.0.0" @@ -3963,49 +4179,9 @@ jsbn@~0.1.0: version "0.1.1" resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" -jscs-jsdoc@^1.3.1: - version "1.3.2" - resolved "https://registry.yarnpkg.com/jscs-jsdoc/-/jscs-jsdoc-1.3.2.tgz#1f2c82b6ab4b97524da958f46b4e562e0305f9a7" - dependencies: - comment-parser "^0.3.1" - jsdoctypeparser "~1.2.0" - -jscs-preset-wikimedia@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/jscs-preset-wikimedia/-/jscs-preset-wikimedia-1.0.0.tgz#fff563342038fc2e8826b7bb7309c3ae3406fc7e" - -jscs@^2.1.1: - version "2.11.0" - resolved "https://registry.yarnpkg.com/jscs/-/jscs-2.11.0.tgz#6e11ef0caaa07731f9dcc2b2b27d8ecee1ddbcb6" - dependencies: - babel-jscs "^2.0.0" - chalk "~1.1.0" - cli-table "~0.3.1" - commander "~2.9.0" - escope "^3.2.0" - esprima "~2.7.0" - estraverse "^4.1.0" - exit "~0.1.2" - glob "^5.0.1" - htmlparser2 "3.8.3" - js-yaml "~3.4.0" - jscs-jsdoc "^1.3.1" - jscs-preset-wikimedia "~1.0.0" - jsonlint "~1.6.2" - lodash "~3.10.0" - minimatch "~3.0.0" - natural-compare "~1.2.2" - pathval "~0.1.1" - prompt "~0.2.14" - reserved-words "^0.1.1" - resolve "^1.1.6" - strip-bom "^2.0.0" - strip-json-comments "~1.0.2" - to-double-quotes "^2.0.0" - to-single-quotes "^2.0.0" - vow "~0.4.8" - vow-fs "~0.3.4" - xmlbuilder "^3.1.0" +jschardet@^1.4.2: + version "1.4.2" + resolved "https://registry.yarnpkg.com/jschardet/-/jschardet-1.4.2.tgz#2aa107f142af4121d145659d44f50830961e699a" jsdoc-75lb@^3.5.6: version "3.6.0" @@ -4079,12 +4255,6 @@ jsdoc2md-stats@^1.0.3: app-usage-stats "^0.4.0" feature-detect-es6 "^1.3.1" -jsdoctypeparser@~1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/jsdoctypeparser/-/jsdoctypeparser-1.2.0.tgz#e7dedc153a11849ffc5141144ae86a7ef0c25392" - dependencies: - lodash "^3.7.0" - jsesc@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-1.3.0.tgz#46c3fec8c1892b12b0833db9bc7622176dbab34b" @@ -4093,34 +4263,14 @@ jsesc@~0.5.0: version "0.5.0" resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d" -jshint-stylish@^2.2.1: - version "2.2.1" - resolved "https://registry.yarnpkg.com/jshint-stylish/-/jshint-stylish-2.2.1.tgz#242082a2c035ae03fd81044e0570cc4208cf6e61" - dependencies: - beeper "^1.1.0" - chalk "^1.0.0" - log-symbols "^1.0.0" - plur "^2.1.0" - string-length "^1.0.0" - text-table "^0.2.0" - -jshint@^2.7.0: - version "2.9.4" - resolved "https://registry.yarnpkg.com/jshint/-/jshint-2.9.4.tgz#5e3ba97848d5290273db514aee47fe24cf592934" - dependencies: - cli "~1.0.0" - console-browserify "1.1.x" - exit "0.1.x" - htmlparser2 "3.8.x" - lodash "3.7.x" - minimatch "~3.0.2" - shelljs "0.3.x" - strip-json-comments "1.0.x" - -json-loader@^0.5.1: +json-loader@^0.5.1, json-loader@^0.5.4: version "0.5.4" resolved "https://registry.yarnpkg.com/json-loader/-/json-loader-0.5.4.tgz#8baa1365a632f58a3c46d20175fc6002c96e37de" +json-schema-traverse@^0.3.0: + version "0.3.1" + resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz#349a6d44c53a51de89b40805c5d5e59b417d3340" + json-schema@0.2.3: version "0.2.3" resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13" @@ -4139,20 +4289,10 @@ json3@3.3.2: version "3.3.2" resolved "https://registry.yarnpkg.com/json3/-/json3-3.3.2.tgz#3c0434743df93e2f5c42aee7b19bcb483575f4e1" -json5@^0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/json5/-/json5-0.4.0.tgz#054352e4c4c80c86c0923877d449de176a732c8d" - -json5@^0.5.0: +json5@^0.5.0, json5@^0.5.1: version "0.5.1" resolved "https://registry.yarnpkg.com/json5/-/json5-0.5.1.tgz#1eade7acc012034ad84e2396767ead9fa5495821" -jsonfile@^2.1.0: - version "2.4.0" - resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-2.4.0.tgz#3736a2b428b87bbda0cc83b53fa3d633a35c2ae8" - optionalDependencies: - graceful-fs "^4.1.6" - jsonfile@~1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-1.0.1.tgz#ea5efe40b83690b98667614a7392fc60e842c0dd" @@ -4161,13 +4301,6 @@ jsonify@~0.0.0: version "0.0.0" resolved "https://registry.yarnpkg.com/jsonify/-/jsonify-0.0.0.tgz#2c74b6ee41d93ca51b7b5aaee8f503631d252a73" -jsonlint@~1.6.2: - version "1.6.2" - resolved "https://registry.yarnpkg.com/jsonlint/-/jsonlint-1.6.2.tgz#5737045085f55eb455c68b1ff4ebc01bd50e8830" - dependencies: - JSV ">= 4.0.x" - nomnom ">= 1.5.x" - jsonpointer@^4.0.0: version "4.0.1" resolved "https://registry.yarnpkg.com/jsonpointer/-/jsonpointer-4.0.1.tgz#4fd92cb34e0e9db3c89c8622ecf51f9b978c6cb9" @@ -4188,32 +4321,30 @@ karma-babel-preprocessor@^6.0.1: babel-core "^6.0.0" karma-browserstack-launcher@^1.0.1: - version "1.2.0" - resolved "https://registry.yarnpkg.com/karma-browserstack-launcher/-/karma-browserstack-launcher-1.2.0.tgz#acfa534835ba590041eef009c1169a219120bb5b" + version "1.3.0" + resolved "https://registry.yarnpkg.com/karma-browserstack-launcher/-/karma-browserstack-launcher-1.3.0.tgz#61fe3d36b1cf10681e40f9d874bf37271fb1c674" dependencies: browserstack "1.5.0" - browserstacktunnel-wrapper "~1.4.2" - q "~1.4.1" + browserstacktunnel-wrapper "~2.0.1" + q "~1.5.0" karma-chai@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/karma-chai/-/karma-chai-0.1.0.tgz#bee5ad40400517811ae34bb945f762909108b79a" -karma-chrome-launcher@^0.2.0: - version "0.2.3" - resolved "https://registry.yarnpkg.com/karma-chrome-launcher/-/karma-chrome-launcher-0.2.3.tgz#4c6d700d163a9d34c618efd87918be49e7a4a8c9" +karma-chrome-launcher@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/karma-chrome-launcher/-/karma-chrome-launcher-2.2.0.tgz#cf1b9d07136cc18fe239327d24654c3dbc368acf" dependencies: fs-access "^1.0.0" which "^1.2.1" -karma-coverage@^0.2.7: - version "0.2.7" - resolved "https://registry.yarnpkg.com/karma-coverage/-/karma-coverage-0.2.7.tgz#f76740b275bbf30a0ab9f41d8cf56843a0994576" +karma-coverage-istanbul-reporter@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/karma-coverage-istanbul-reporter/-/karma-coverage-istanbul-reporter-1.3.0.tgz#d142cd9c55731c9e363ef7374e8ef1a31bebfadb" dependencies: - dateformat "~1.0.6" - ibrik "~2.0.0" - istanbul "~0.3.0" - minimatch "~0.3.0" + istanbul-api "^1.1.8" + minimatch "^3.0.4" karma-es5-shim@^0.0.4: version "0.0.4" @@ -4227,69 +4358,64 @@ karma-expect@^1.1.0: dependencies: expect.js "^0.3.1" -karma-firefox-launcher@^0.1.3: - version "0.1.7" - resolved "https://registry.yarnpkg.com/karma-firefox-launcher/-/karma-firefox-launcher-0.1.7.tgz#c05dd86533691e62f31952595098e8bd357d39f3" - -karma-html-reporter@^0.2.7: - version "0.2.7" - resolved "https://registry.yarnpkg.com/karma-html-reporter/-/karma-html-reporter-0.2.7.tgz#fd73da9f1ac99fd5bafb309cf070942188e7ba63" - dependencies: - lodash "~2.2.0" - mu2 "~0.5.19" - -karma-ie-launcher@^0.1.5: - version "0.1.5" - resolved "https://registry.yarnpkg.com/karma-ie-launcher/-/karma-ie-launcher-0.1.5.tgz#ee43bd238f61c45dd8fbc1694b13a50dfb5a3e1b" +karma-firefox-launcher@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/karma-firefox-launcher/-/karma-firefox-launcher-1.0.1.tgz#ce58f47c2013a88156d55a5d61337c099cf5bb51" -karma-junit-reporter@^0.3.8: - version "0.3.8" - resolved "https://registry.yarnpkg.com/karma-junit-reporter/-/karma-junit-reporter-0.3.8.tgz#d24b85b8507b7ddb2c8ced0d1f4f2b1ac700d3fe" +karma-ie-launcher@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/karma-ie-launcher/-/karma-ie-launcher-1.0.0.tgz#497986842c490190346cd89f5494ca9830c6d59c" dependencies: - xmlbuilder "3.1.0" + lodash "^4.6.1" karma-mocha@^0.2.0: version "0.2.2" resolved "https://registry.yarnpkg.com/karma-mocha/-/karma-mocha-0.2.2.tgz#388ed917da15dcb196d1b915c1934ef803193f8e" -karma-opera-launcher@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/karma-opera-launcher/-/karma-opera-launcher-0.1.0.tgz#751c89db4e686a8327d291f19a58b34f00dbd078" - -karma-phantomjs-launcher@^0.2.1: - version "0.2.3" - resolved "https://registry.yarnpkg.com/karma-phantomjs-launcher/-/karma-phantomjs-launcher-0.2.3.tgz#77f68243fad7852c5b321bcf9d691f1223cc0809" - dependencies: - lodash "^3.10.1" +karma-opera-launcher@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/karma-opera-launcher/-/karma-opera-launcher-1.0.0.tgz#fa51628531a1d0be84b2d8dc0d7ee209fc8ff91a" -karma-requirejs@^0.2.2: - version "0.2.6" - resolved "https://registry.yarnpkg.com/karma-requirejs/-/karma-requirejs-0.2.6.tgz#1a770c64f901320a389c65b4944746326372def8" +karma-requirejs@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/karma-requirejs/-/karma-requirejs-1.1.0.tgz#fddae2cb87d7ebc16fb0222893564d7fee578798" -karma-safari-launcher@^0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/karma-safari-launcher/-/karma-safari-launcher-0.1.1.tgz#a6380accab60a583fdd624f41b9a3f10fdf41008" +karma-safari-launcher@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/karma-safari-launcher/-/karma-safari-launcher-1.0.0.tgz#96982a2cc47d066aae71c553babb28319115a2ce" -karma-sauce-launcher@^0.2.10: - version "0.2.14" - resolved "https://registry.yarnpkg.com/karma-sauce-launcher/-/karma-sauce-launcher-0.2.14.tgz#e42e412517c5f40534c8bba7d14bb4f10727b6a7" +karma-sauce-launcher@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/karma-sauce-launcher/-/karma-sauce-launcher-1.1.0.tgz#3d083cf5659d6736ab97bcee5d8acd86ad522212" dependencies: - q "~0.9.6" - sauce-connect-launcher "~0.11.1" - saucelabs "~0.1.0" - wd "~0.3.4" + q "^1.4.1" + sauce-connect-launcher "^0.17.0" + saucelabs "^1.3.0" + wd "^1.0.0" -karma-script-launcher@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/karma-script-launcher/-/karma-script-launcher-0.1.0.tgz#b643e7c2faead1a52cdb2eeaadcf7a245f0d772a" +karma-script-launcher@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/karma-script-launcher/-/karma-script-launcher-1.0.0.tgz#cd017c4de5ef09e5a9da793276176108dd4b542d" -karma-sinon-ie@^2.0.0-rc10: +karma-sinon-ie@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/karma-sinon-ie/-/karma-sinon-ie-2.0.0.tgz#d07f05ac911baea5f6dbc95e1404fd9c93f6cc65" -karma-webpack@^1.5.1: - version "1.8.1" - resolved "https://registry.yarnpkg.com/karma-webpack/-/karma-webpack-1.8.1.tgz#39d5fd2edeea3cc3ef5b405989b37d5b0e6a3b4e" +karma-sourcemap-loader@^0.3.7: + version "0.3.7" + resolved "https://registry.yarnpkg.com/karma-sourcemap-loader/-/karma-sourcemap-loader-0.3.7.tgz#91322c77f8f13d46fed062b042e1009d4c4505d8" + dependencies: + graceful-fs "^4.1.2" + +karma-spec-reporter@^0.0.31: + version "0.0.31" + resolved "https://registry.yarnpkg.com/karma-spec-reporter/-/karma-spec-reporter-0.0.31.tgz#4830dc7148a155c7d7a186e632339a0d80fadec3" + dependencies: + colors "^1.1.2" + +karma-webpack@^2.0.3: + version "2.0.4" + resolved "https://registry.yarnpkg.com/karma-webpack/-/karma-webpack-2.0.4.tgz#3e2d4f48ba94a878e1c66bb8e1ae6128987a175b" dependencies: async "~0.9.0" loader-utils "^0.2.5" @@ -4297,45 +4423,51 @@ karma-webpack@^1.5.1: source-map "^0.1.41" webpack-dev-middleware "^1.0.11" -karma@^0.13.2: - version "0.13.22" - resolved "https://registry.yarnpkg.com/karma/-/karma-0.13.22.tgz#07750b1bd063d7e7e7b91bcd2e6354d8f2aa8744" +karma@^1.7.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/karma/-/karma-1.7.0.tgz#6f7a1a406446fa2e187ec95398698f4cee476269" dependencies: - batch "^0.5.3" - bluebird "^2.9.27" - body-parser "^1.12.4" + bluebird "^3.3.0" + body-parser "^1.16.1" chokidar "^1.4.1" colors "^1.1.0" - connect "^3.3.5" - core-js "^2.1.0" + combine-lists "^1.0.0" + connect "^3.6.0" + core-js "^2.2.0" di "^0.0.1" dom-serialize "^2.2.0" expand-braces "^0.1.1" - glob "^7.0.0" + glob "^7.1.1" graceful-fs "^4.1.2" http-proxy "^1.13.0" isbinaryfile "^3.0.0" lodash "^3.8.0" log4js "^0.6.31" mime "^1.3.4" - minimatch "^3.0.0" + minimatch "^3.0.2" optimist "^0.6.1" - rimraf "^2.3.3" - socket.io "^1.4.5" + qjobs "^1.1.4" + range-parser "^1.2.0" + rimraf "^2.6.0" + safe-buffer "^5.0.1" + socket.io "1.7.3" source-map "^0.5.3" - useragent "^2.1.6" - -kew@~0.7.0: - version "0.7.0" - resolved "https://registry.yarnpkg.com/kew/-/kew-0.7.0.tgz#79d93d2d33363d6fdd2970b335d9141ad591d79b" + tmp "0.0.31" + useragent "^2.1.12" kind-of@^3.0.2: - version "3.1.0" - resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.1.0.tgz#475d698a5e49ff5e53d14e3e732429dc8bf4cf47" + version "3.2.2" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64" + dependencies: + is-buffer "^1.1.5" + +kind-of@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-4.0.0.tgz#20813df3d712928b207378691a45066fae72dd57" dependencies: - is-buffer "^1.0.2" + is-buffer "^1.1.5" -klaw@^1.0.0, klaw@~1.3.0: +klaw@~1.3.0: version "1.3.1" resolved "https://registry.yarnpkg.com/klaw/-/klaw-1.3.1.tgz#4088433b46b3b1ba259d78785d8e96f73ba02439" optionalDependencies: @@ -4345,6 +4477,12 @@ lazy-cache@^1.0.3: version "1.0.4" resolved "https://registry.yarnpkg.com/lazy-cache/-/lazy-cache-1.0.4.tgz#a1d78fc3a50474cb80845d3b3b6e1da49a446e8e" +lazystream@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/lazystream/-/lazystream-1.0.0.tgz#f6995fe0f820392f61396be89462407bb77168e4" + dependencies: + readable-stream "^2.0.5" + lazystream@~0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/lazystream/-/lazystream-0.1.0.tgz#1b25d63c772a4c20f0a5ed0a9d77f484b6e16920" @@ -4361,16 +4499,12 @@ lcov-parse@0.0.10: version "0.0.10" resolved "https://registry.yarnpkg.com/lcov-parse/-/lcov-parse-0.0.10.tgz#1b0b8ff9ac9c7889250582b70b71315d9da6d9a3" -leven@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/leven/-/leven-1.0.2.tgz#9144b6eebca5f1d0680169f1a6770dcea60b75c3" - -levn@~0.2.5: - version "0.2.5" - resolved "https://registry.yarnpkg.com/levn/-/levn-0.2.5.tgz#ba8d339d0ca4a610e3a3f145b9caf48807155054" +levn@^0.3.0, levn@~0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee" dependencies: - prelude-ls "~1.1.0" - type-check "~0.3.1" + prelude-ls "~1.1.2" + type-check "~0.3.2" liftoff@^2.1.0: version "2.3.0" @@ -4400,6 +4534,19 @@ load-json-file@^1.0.0: pinkie-promise "^2.0.0" strip-bom "^2.0.0" +load-json-file@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-2.0.0.tgz#7947e42149af80d696cbf797bcaabcfe1fe29ca8" + dependencies: + graceful-fs "^4.1.2" + parse-json "^2.2.0" + pify "^2.0.0" + strip-bom "^3.0.0" + +loader-runner@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-2.3.0.tgz#f482aea82d543e07921700d5a46ef26fdac6b8a2" + loader-utils@^0.2.11, loader-utils@^0.2.16, loader-utils@^0.2.5, loader-utils@~0.2.2, loader-utils@~0.2.3, loader-utils@~0.2.5: version "0.2.17" resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-0.2.17.tgz#f86e6374d43205a6e6c60e9196f17c0299bfb348" @@ -4409,15 +4556,30 @@ loader-utils@^0.2.11, loader-utils@^0.2.16, loader-utils@^0.2.5, loader-utils@~0 json5 "^0.5.0" object-assign "^4.0.1" +loader-utils@^1.0.2, loader-utils@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-1.1.0.tgz#c98aef488bcceda2ffb5e2de646d6a754429f5cd" + dependencies: + big.js "^3.1.3" + emojis-list "^2.0.0" + json5 "^0.5.0" + localtunnel@^1.3.0: - version "1.8.2" - resolved "https://registry.yarnpkg.com/localtunnel/-/localtunnel-1.8.2.tgz#913051e8328b51f75ad8a22ad1f5c5b8c599a359" + version "1.8.3" + resolved "https://registry.yarnpkg.com/localtunnel/-/localtunnel-1.8.3.tgz#dcc5922fd85651037d4bde24fd93248d0b24eb05" dependencies: - debug "2.2.0" - openurl "1.1.0" - request "2.78.0" + debug "2.6.8" + openurl "1.1.1" + request "2.81.0" yargs "3.29.0" +locate-path@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-2.0.0.tgz#2b568b265eec944c6d9c0de9c3dbbbca0354cd8e" + dependencies: + p-locate "^2.0.0" + path-exists "^3.0.0" + lodash._arraycopy@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/lodash._arraycopy/-/lodash._arraycopy-3.0.0.tgz#76e7b7c1f1fb92547374878a562ed06a3e50f6e1" @@ -4472,14 +4634,6 @@ lodash._bindcallback@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/lodash._bindcallback/-/lodash._bindcallback-3.0.1.tgz#e531c27644cf8b57a99e17ed95b35c748789392e" -lodash._createassigner@^3.0.0: - version "3.1.1" - resolved "https://registry.yarnpkg.com/lodash._createassigner/-/lodash._createassigner-3.1.1.tgz#838a5bae2fdaca63ac22dee8e19fa4e6d6970b11" - dependencies: - lodash._bindcallback "^3.0.0" - lodash._isiterateecall "^3.0.0" - lodash.restparam "^3.0.0" - lodash._escapehtmlchar@~2.4.1: version "2.4.1" resolved "https://registry.yarnpkg.com/lodash._escapehtmlchar/-/lodash._escapehtmlchar-2.4.1.tgz#df67c3bb6b7e8e1e831ab48bfa0795b92afe899d" @@ -4547,22 +4701,10 @@ lodash._stack@^4.0.0: version "4.1.3" resolved "https://registry.yarnpkg.com/lodash._stack/-/lodash._stack-4.1.3.tgz#751aa76c1b964b047e76d14fc72a093fcb5e2dd0" -lodash.assign@^3.2.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/lodash.assign/-/lodash.assign-3.2.0.tgz#3ce9f0234b4b2223e296b8fa0ac1fee8ebca64fa" - dependencies: - lodash._baseassign "^3.0.0" - lodash._createassigner "^3.0.0" - lodash.keys "^3.0.0" - -lodash.assign@^4.0.3, lodash.assign@^4.0.6: +lodash.assign@*, lodash.assign@^4.0.3, lodash.assign@^4.0.6: version "4.2.0" resolved "https://registry.yarnpkg.com/lodash.assign/-/lodash.assign-4.2.0.tgz#0d99f3ccd7a6d261d19bdaeb9245005d285808e7" -lodash.assignwith@^4.0.7: - version "4.2.0" - resolved "https://registry.yarnpkg.com/lodash.assignwith/-/lodash.assignwith-4.2.0.tgz#127a97f02adc41751a954d24b0de17e100e038eb" - lodash.clone@3.0.3: version "3.0.3" resolved "https://registry.yarnpkg.com/lodash.clone/-/lodash.clone-3.0.3.tgz#84688c73d32b5a90ca25616963f189252a997043" @@ -4575,9 +4717,9 @@ lodash.clone@^4.3.2: version "4.5.0" resolved "https://registry.yarnpkg.com/lodash.clone/-/lodash.clone-4.5.0.tgz#195870450f5a13192478df4bc3d23d2dea1907b6" -lodash.clonedeep@^4.3.2: - version "4.5.0" - resolved "https://registry.yarnpkg.com/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz#e23f3f9c4f8fbdde872529c1071857a086e5ccef" +lodash.cond@^4.3.0: + version "4.5.2" + resolved "https://registry.yarnpkg.com/lodash.cond/-/lodash.cond-4.5.2.tgz#f471a1da486be60f6ab955d17115523dd1d255d5" lodash.create@3.1.1: version "3.1.1" @@ -4627,10 +4769,6 @@ lodash.isarray@^3.0.0: version "3.0.4" resolved "https://registry.yarnpkg.com/lodash.isarray/-/lodash.isarray-3.0.4.tgz#79e4eb88c36a8122af86f844aa9bcd851b5fbb55" -lodash.isempty@^4.2.1: - version "4.4.0" - resolved "https://registry.yarnpkg.com/lodash.isempty/-/lodash.isempty-4.4.0.tgz#6f86cbedd8be4ec987be9aaf33c9684db1b31e7e" - lodash.isobject@~2.4.1: version "2.4.1" resolved "https://registry.yarnpkg.com/lodash.isobject/-/lodash.isobject-2.4.1.tgz#5a2e47fe69953f1ee631a7eba1fe64d2d06558f5" @@ -4673,7 +4811,7 @@ lodash.mergewith@^4.0.0: version "4.6.0" resolved "https://registry.yarnpkg.com/lodash.mergewith/-/lodash.mergewith-4.6.0.tgz#150cf0a16791f5903b8891eab154609274bdea55" -lodash.pick@^4.2.1, lodash.pick@^4.4.0: +lodash.pick@^4.4.0: version "4.4.0" resolved "https://registry.yarnpkg.com/lodash.pick/-/lodash.pick-4.4.0.tgz#52f05610fff9ded422611441ed1fc123a03001b3" @@ -4735,19 +4873,15 @@ lodash.values@~2.4.1: dependencies: lodash.keys "~2.4.1" -lodash@3.5.0: - version "3.5.0" - resolved "https://registry.yarnpkg.com/lodash/-/lodash-3.5.0.tgz#19bb3f4d51278f0b8c818ed145c74ecf9fe40e6d" - -lodash@3.7.x: - version "3.7.0" - resolved "https://registry.yarnpkg.com/lodash/-/lodash-3.7.0.tgz#3678bd8ab995057c07ade836ed2ef087da811d45" - -lodash@^3.0.1, lodash@^3.10.0, lodash@^3.10.1, lodash@^3.3.1, lodash@^3.5.0, lodash@^3.7.0, lodash@^3.8.0, lodash@^3.9.3, lodash@~3.10.0: +lodash@3.10.1, lodash@^3.3.1, lodash@^3.8.0: version "3.10.1" resolved "https://registry.yarnpkg.com/lodash/-/lodash-3.10.1.tgz#5bf45e8e49ba4189e17d482789dfd15bd140b7b6" -lodash@^4.0.0, lodash@^4.14.0, lodash@^4.16.2, lodash@^4.17.4, lodash@^4.2.0: +lodash@4.16.2: + version "4.16.2" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.16.2.tgz#3e626db827048a699281a8a125226326cfc0e652" + +lodash@^4.0.0, lodash@^4.13.1, lodash@^4.14.0, lodash@^4.16.2, lodash@^4.17.4, lodash@^4.2.0, lodash@^4.3.0, lodash@^4.5.0, lodash@^4.6.1, lodash@^4.8.0: version "4.17.4" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.4.tgz#78203a4d1c328ae1d86dca6460e369b57f4055ae" @@ -4755,32 +4889,14 @@ lodash@~1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/lodash/-/lodash-1.0.2.tgz#8f57560c83b59fc270bd3d561b690043430e2551" -lodash@~2.2.0: - version "2.2.1" - resolved "https://registry.yarnpkg.com/lodash/-/lodash-2.2.1.tgz#ca935fd14ab3c0c872abacf198b9cda501440867" - -lodash@~2.4.1: - version "2.4.2" - resolved "https://registry.yarnpkg.com/lodash/-/lodash-2.4.2.tgz#fadd834b9683073da179b3eae6d9c0d15053f73e" - lodash@~3.2.0: version "3.2.0" resolved "https://registry.yarnpkg.com/lodash/-/lodash-3.2.0.tgz#4bf50a3243f9aeb0bac41a55d3d5990675a462fb" -lodash@~3.9.3: - version "3.9.3" - resolved "https://registry.yarnpkg.com/lodash/-/lodash-3.9.3.tgz#0159e86832feffc6d61d852b12a953b99496bd32" - log-driver@1.2.5: version "1.2.5" resolved "https://registry.yarnpkg.com/log-driver/-/log-driver-1.2.5.tgz#7ae4ec257302fd790d557cb10c97100d857b0056" -log-symbols@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-1.0.2.tgz#376ff7b58ea3086a0f09facc74617eca501e1a18" - dependencies: - chalk "^1.0.0" - log4js@^0.6.31: version "0.6.38" resolved "https://registry.yarnpkg.com/log4js/-/log4js-0.6.38.tgz#2c494116695d6fb25480943d3fc872e662a522fd" @@ -4809,7 +4925,11 @@ loud-rejection@^1.0.0: currently-unhandled "^0.4.1" signal-exit "^3.0.0" -lru-cache@2, lru-cache@2.2.x: +lru-cache@2: + version "2.7.3" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-2.7.3.tgz#6d4524e8b955f95d4f5b58851ce21dd72fb4e952" + +lru-cache@2.2.x: version "2.2.4" resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-2.2.4.tgz#6c658619becf14031d0d0b594b16042ce4dc063d" @@ -4817,12 +4937,34 @@ lru-cache@~2.6.5: version "2.6.5" resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-2.6.5.tgz#e56d6354148ede8d7707b58d143220fd08df0fd5" +lru-queue@0.1: + version "0.1.0" + resolved "https://registry.yarnpkg.com/lru-queue/-/lru-queue-0.1.0.tgz#2738bd9f0d3cf4f84490c5736c48699ac632cda3" + dependencies: + es5-ext "~0.10.2" + magic-string@^0.16.0: version "0.16.0" resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.16.0.tgz#970ebb0da7193301285fb1aa650f39bdd81eb45a" dependencies: vlq "^0.2.1" +make-dir@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-1.0.0.tgz#97a011751e91dd87cfadef58832ebb04936de978" + dependencies: + pify "^2.3.0" + +make-error-cause@^1.1.1: + version "1.2.2" + resolved "https://registry.yarnpkg.com/make-error-cause/-/make-error-cause-1.2.2.tgz#df0388fcd0b37816dff0a5fb8108939777dcbc9d" + dependencies: + make-error "^1.2.0" + +make-error@^1.2.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.0.tgz#52ad3a339ccf10ce62b4040b708fe707244b8b96" + map-cache@^0.2.0: version "0.2.2" resolved "https://registry.yarnpkg.com/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf" @@ -4854,6 +4996,19 @@ media-typer@0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" +memoizee@^0.4.5: + version "0.4.5" + resolved "https://registry.yarnpkg.com/memoizee/-/memoizee-0.4.5.tgz#1bc3ea1e4be056dd475d521979d7be3d5e5b21c8" + dependencies: + d "1" + es5-ext "^0.10.13" + es6-weak-map "^2.0.1" + event-emitter "^0.3.4" + is-promise "^2.1" + lru-queue "0.1" + next-tick "1" + timers-ext "0.1" + memory-fs@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/memory-fs/-/memory-fs-0.2.0.tgz#f2bb25368bc121e391c2520de92969caee0a0290" @@ -4865,7 +5020,7 @@ memory-fs@^0.3.0, memory-fs@~0.3.0: errno "^0.1.3" readable-stream "^2.0.1" -memory-fs@~0.4.1: +memory-fs@^0.4.0, memory-fs@~0.4.1: version "0.4.1" resolved "https://registry.yarnpkg.com/memory-fs/-/memory-fs-0.4.1.tgz#3a9a20b8462523e447cfbc7e8bb80ed667bfc552" dependencies: @@ -4891,14 +5046,20 @@ merge-descriptors@~1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" +merge-stream@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-1.0.1.tgz#4041202d508a342ba00174008df0c251b8c135e1" + dependencies: + readable-stream "^2.0.1" + method-override@~2.3.5: - version "2.3.8" - resolved "https://registry.yarnpkg.com/method-override/-/method-override-2.3.8.tgz#178234bf4bab869f89df9444b06fc6147b44828c" + version "2.3.9" + resolved "https://registry.yarnpkg.com/method-override/-/method-override-2.3.9.tgz#bd151f2ce34cf01a76ca400ab95c012b102d8f71" dependencies: - debug "2.6.3" + debug "2.6.8" methods "~1.1.2" parseurl "~1.3.1" - vary "~1.1.0" + vary "~1.1.1" methods@~1.1.2: version "1.1.2" @@ -4922,15 +5083,18 @@ micromatch@^2.1.5, micromatch@^2.3.7: parse-glob "^3.0.4" regex-cache "^0.4.2" +miller-rabin@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/miller-rabin/-/miller-rabin-4.0.0.tgz#4a62fb1d42933c05583982f4c716f6fb9e6c6d3d" + dependencies: + bn.js "^4.0.0" + brorand "^1.0.1" + "mime-db@>= 1.27.0 < 2", mime-db@~1.27.0: version "1.27.0" resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.27.0.tgz#820f572296bbd20ec25ed55e5b5de869e5436eb1" -mime-db@~1.12.0: - version "1.12.0" - resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.12.0.tgz#3d0c63180f458eb10d325aaa37d7c58ae312e9d7" - -mime-types@^2.1.11, mime-types@^2.1.12, mime-types@~2.1.11, mime-types@~2.1.15, mime-types@~2.1.6, mime-types@~2.1.7, mime-types@~2.1.9: +mime-types@^2.1.12, mime-types@~2.1.11, mime-types@~2.1.15, mime-types@~2.1.6, mime-types@~2.1.7, mime-types@~2.1.9: version "2.1.15" resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.15.tgz#a4ebf5064094569237b8cf70046776d09fc92aed" dependencies: @@ -4940,34 +5104,43 @@ mime-types@~1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-1.0.2.tgz#995ae1392ab8affcbfcb2641dd054e943c0d5dce" -mime-types@~2.0.1, mime-types@~2.0.3: - version "2.0.14" - resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.0.14.tgz#310e159db23e077f8bb22b748dabfa4957140aa6" - dependencies: - mime-db "~1.12.0" - -mime@1.3.4, mime@^1.3.4: +mime@1.3.4: version "1.3.4" resolved "https://registry.yarnpkg.com/mime/-/mime-1.3.4.tgz#115f9e3b6b3daf2959983cb38f149a2d40eb5d53" +mime@^1.3.4: + version "1.3.6" + resolved "https://registry.yarnpkg.com/mime/-/mime-1.3.6.tgz#591d84d3653a6b0b4a3b9df8de5aa8108e72e5e0" + mime@~1.2.11: version "1.2.11" resolved "https://registry.yarnpkg.com/mime/-/mime-1.2.11.tgz#58203eed86e3a5ef17aed2b7d9ebd47f0a60dd10" -minimatch@0.3, minimatch@0.x, minimatch@~0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-0.3.0.tgz#275d8edaac4f1bb3326472089e7949c8394699dd" +mimic-fn@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-1.1.0.tgz#e667783d92e89dbd342818b5230b9d62a672ad18" + +minimalistic-assert@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.0.tgz#702be2dda6b37f4836bcb3f5db56641b64a1d3d3" + +minimalistic-crypto-utils@^1.0.0, minimalistic-crypto-utils@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a" + +"minimatch@2 || 3", minimatch@^3.0.0, minimatch@^3.0.2, minimatch@^3.0.3, minimatch@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" dependencies: - lru-cache "2" - sigmund "~1.0.0" + brace-expansion "^1.1.7" -"minimatch@2 || 3", minimatch@3.0.3, minimatch@^3.0.0, minimatch@^3.0.2, minimatch@~3.0.0, minimatch@~3.0.2: +minimatch@3.0.3: version "3.0.3" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.3.tgz#2a4e4090b96b2db06a9d7df01055a62a77c9b774" dependencies: brace-expansion "^1.0.0" -minimatch@2.x, minimatch@^2.0.1, minimatch@^2.0.3: +minimatch@^2.0.1: version "2.0.10" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-2.0.10.tgz#8d087c39c6b38c001b97fca7ce6d0e1e80afbac7" dependencies: @@ -4992,6 +5165,10 @@ minimist@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.2.0.tgz#4dffe525dae2b864c66c2e23c6271d7afdecefce" +mkdirp2@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/mkdirp2/-/mkdirp2-1.0.3.tgz#cc8dd8265f1f06e2d8f5b10b6e52f4e050bed21b" + mkdirp@0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.3.0.tgz#1bbf5ab1ba827af23575143490426455f481fe1e" @@ -5000,7 +5177,7 @@ mkdirp@0.3.x, mkdirp@~0.3.5: version "0.3.5" resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.3.5.tgz#de3e5f8961c88c787ee1368df849ac4413eca8d7" -mkdirp@0.5, mkdirp@0.5.1, mkdirp@0.5.x, mkdirp@0.x.x, "mkdirp@>=0.5 0", mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@~0.5.0, mkdirp@~0.5.1: +mkdirp@0.5, mkdirp@0.5.1, mkdirp@0.5.x, "mkdirp@>=0.5 0", mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@~0.5.0, mkdirp@~0.5.1: version "0.5.1" resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" dependencies: @@ -5016,9 +5193,9 @@ mkpath@1.0.0, mkpath@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/mkpath/-/mkpath-1.0.0.tgz#ebb3a977e7af1c683ae6fda12b545a6ba6c5853d" -mocha-nightwatch@3.2.1: - version "3.2.1" - resolved "https://registry.yarnpkg.com/mocha-nightwatch/-/mocha-nightwatch-3.2.1.tgz#0e810f9c958d91bc3982c5948044a91436182c29" +mocha-nightwatch@3.2.2: + version "3.2.2" + resolved "https://registry.yarnpkg.com/mocha-nightwatch/-/mocha-nightwatch-3.2.2.tgz#91bcb9b3bde057dd7677c78125e491e58d66647c" dependencies: browser-stdout "1.3.0" commander "2.9.0" @@ -5045,21 +5222,6 @@ mocha@^1.21.4: jade "0.26.3" mkdirp "0.5.0" -mocha@^2.0.1: - version "2.5.3" - resolved "https://registry.yarnpkg.com/mocha/-/mocha-2.5.3.tgz#161be5bdeb496771eb9b35745050b622b5aefc58" - dependencies: - commander "2.3.0" - debug "2.2.0" - diff "1.4.0" - escape-string-regexp "1.0.2" - glob "3.2.11" - growl "1.9.2" - jade "0.26.3" - mkdirp "0.5.1" - supports-color "1.2.0" - to-iso-string "0.0.2" - mock-fs@^3.11.0: version "3.12.1" resolved "https://registry.yarnpkg.com/mock-fs/-/mock-fs-3.12.1.tgz#ff27824cd6ab263a7eb05a115239d41d3631f5f8" @@ -5093,9 +5255,9 @@ ms@0.7.2: version "0.7.2" resolved "https://registry.yarnpkg.com/ms/-/ms-0.7.2.tgz#ae25cf2512b3885a1d95d7f037868d8431124765" -mu2@~0.5.19: - version "0.5.21" - resolved "https://registry.yarnpkg.com/mu2/-/mu2-0.5.21.tgz#888a8f0fd90eb1cfda9db81476f6e199cc9e58d3" +ms@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" multiparty@3.3.2: version "3.3.2" @@ -5114,23 +5276,23 @@ mute-stream@0.0.4: version "0.0.4" resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.4.tgz#a9219960a6d5d5d046597aee51252c6655f7177e" -mute-stream@~0.0.4: +mute-stream@0.0.7: version "0.0.7" resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.7.tgz#3075ce93bc21b8fab43e1bc4da7e8115ed1e7bab" nan@^2.3.0: - version "2.6.1" - resolved "https://registry.yarnpkg.com/nan/-/nan-2.6.1.tgz#8c84f7b14c96b89f57fbc838012180ec8ca39a01" + version "2.6.2" + resolved "https://registry.yarnpkg.com/nan/-/nan-2.6.2.tgz#e4ff34e6c95fdfb5aecc08de6596f43605a7db45" natives@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/natives/-/natives-1.1.0.tgz#e9ff841418a6b2ec7a495e939984f78f163e6e31" -natural-compare@~1.2.2: - version "1.2.2" - resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.2.2.tgz#1f96d60e3141cac1b6d05653ce0daeac763af6aa" +natural-compare@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" -ncp@0.4.x, ncp@~0.4.2: +ncp@~0.4.2: version "0.4.2" resolved "https://registry.yarnpkg.com/ncp/-/ncp-0.4.2.tgz#abcc6cbd3ec2ed2a729ff6e7c1fa8f01784a8574" @@ -5146,9 +5308,13 @@ netmask@~1.0.4: version "1.0.6" resolved "https://registry.yarnpkg.com/netmask/-/netmask-1.0.6.tgz#20297e89d86f6f6400f250d9f4f6b4c1945fcd35" +next-tick@1: + version "1.0.0" + resolved "https://registry.yarnpkg.com/next-tick/-/next-tick-1.0.0.tgz#ca86d1fe8828169b0120208e3dc8424b9db8342c" + nightwatch@^0.9.5: - version "0.9.14" - resolved "https://registry.yarnpkg.com/nightwatch/-/nightwatch-0.9.14.tgz#897eb2e418b75492c3671e28e8e413abe17cc268" + version "0.9.16" + resolved "https://registry.yarnpkg.com/nightwatch/-/nightwatch-0.9.16.tgz#c4ac3ec711b0ff047c3dca9c6557365ee236519f" dependencies: chai-nightwatch "~0.1.x" ejs "0.8.3" @@ -5156,7 +5322,7 @@ nightwatch@^0.9.5: lodash.defaultsdeep "4.3.2" minimatch "3.0.3" mkpath "1.0.0" - mocha-nightwatch "3.2.1" + mocha-nightwatch "3.2.2" optimist "0.6.1" proxy-agent "2.0.0" q "1.4.1" @@ -5193,9 +5359,37 @@ node-libs-browser@^0.7.0: util "^0.10.3" vm-browserify "0.0.4" -node-pre-gyp@^0.6.29: - version "0.6.34" - resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.6.34.tgz#94ad1c798a11d7fc67381b50d47f8cc18d9799f7" +node-libs-browser@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/node-libs-browser/-/node-libs-browser-2.0.0.tgz#a3a59ec97024985b46e958379646f96c4b616646" + dependencies: + assert "^1.1.1" + browserify-zlib "^0.1.4" + buffer "^4.3.0" + console-browserify "^1.1.0" + constants-browserify "^1.0.0" + crypto-browserify "^3.11.0" + domain-browser "^1.1.1" + events "^1.0.0" + https-browserify "0.0.1" + os-browserify "^0.2.0" + path-browserify "0.0.0" + process "^0.11.0" + punycode "^1.2.4" + querystring-es3 "^0.2.0" + readable-stream "^2.0.5" + stream-browserify "^2.0.1" + stream-http "^2.3.1" + string_decoder "^0.10.25" + timers-browserify "^2.0.2" + tty-browserify "0.0.0" + url "^0.11.0" + util "^0.10.3" + vm-browserify "0.0.4" + +node-pre-gyp@^0.6.36: + version "0.6.36" + resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.6.36.tgz#db604112cb74e0d477554e9b505b17abddfab786" dependencies: mkdirp "^0.5.1" nopt "^4.0.1" @@ -5207,17 +5401,10 @@ node-pre-gyp@^0.6.29: tar "^2.2.1" tar-pack "^3.4.0" -node-uuid@~1.4.0, node-uuid@~1.4.7: +node-uuid@~1.4.0: version "1.4.8" resolved "https://registry.yarnpkg.com/node-uuid/-/node-uuid-1.4.8.tgz#b040eb0923968afabf8d32fb1f17f1167fdab907" -"nomnom@>= 1.5.x": - version "1.8.1" - resolved "https://registry.yarnpkg.com/nomnom/-/nomnom-1.8.1.tgz#2151f722472ba79e50a76fc125bb8c8f2e4dc2a7" - dependencies: - chalk "~0.4.0" - underscore "~1.6.0" - nopt@3.x: version "3.0.6" resolved "https://registry.yarnpkg.com/nopt/-/nopt-3.0.6.tgz#c6465dbf08abcd4db359317f79ac68a646b28ff9" @@ -5232,27 +5419,27 @@ nopt@^4.0.1: osenv "^0.1.4" normalize-package-data@^2.3.2, normalize-package-data@^2.3.4: - version "2.3.6" - resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.3.6.tgz#498fa420c96401f787402ba21e600def9f981fff" + version "2.4.0" + resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.4.0.tgz#12f95a307d58352075a04907b84ac8be98ac012f" dependencies: hosted-git-info "^2.1.4" is-builtin-module "^1.0.0" semver "2 || 3 || 4 || 5" validate-npm-package-license "^3.0.1" -normalize-path@^2.0.1: +normalize-path@^2.0.0, normalize-path@^2.0.1, normalize-path@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9" dependencies: remove-trailing-separator "^1.0.1" npmlog@^4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.0.2.tgz#d03950e0e78ce1527ba26d2a7592e9348ac3e75f" + version "4.1.2" + resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b" dependencies: are-we-there-yet "~1.1.2" console-control-strings "~1.1.0" - gauge "~2.7.1" + gauge "~2.7.3" set-blocking "~2.0.0" null-check@^1.0.0: @@ -5267,11 +5454,7 @@ oauth-sign@~0.5.0: version "0.5.0" resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.5.0.tgz#d767f5169325620eab2e087ef0c472e773db6461" -oauth-sign@~0.6.0: - version "0.6.0" - resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.6.0.tgz#7dbeae44f6ca454e1f168451d630746735813ce3" - -oauth-sign@~0.8.0, oauth-sign@~0.8.1: +oauth-sign@~0.8.1: version "0.8.2" resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.8.2.tgz#46a6ab7f0aead8deae9ec0565780b7d4efeb9d43" @@ -5291,7 +5474,7 @@ object-component@0.0.3: version "0.0.3" resolved "https://registry.yarnpkg.com/object-component/-/object-component-0.0.3.tgz#f0c69aa50efc95b866c186f400a33769cb2f1291" -object-get@^2.0.0, object-get@^2.0.2, object-get@^2.0.4, object-get@^2.1.0: +object-get@^2.0.0, object-get@^2.0.2, object-get@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/object-get/-/object-get-2.1.0.tgz#722bbdb60039efa47cad3c6dc2ce51a85c02c5ae" @@ -5300,8 +5483,8 @@ object-keys@~0.4.0: resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-0.4.0.tgz#28a6aae7428dd2c3a92f3d95f21335dd204e0336" object-to-spawn-args@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/object-to-spawn-args/-/object-to-spawn-args-1.1.0.tgz#031a200e37db2c3dfc9b98074a0d69a5be253c1c" + version "1.1.1" + resolved "https://registry.yarnpkg.com/object-to-spawn-args/-/object-to-spawn-args-1.1.1.tgz#77da8827f073d011c9e1b173f895781470246785" object-tools@^1.2.1, object-tools@^1.6.1: version "1.6.7" @@ -5320,6 +5503,15 @@ object-tools@^2, object-tools@^2.0.6: test-value "^1.1.0" typical "^2.4.2" +object.defaults@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/object.defaults/-/object.defaults-1.1.0.tgz#3a7f868334b407dea06da16d88d5cd29e435fecf" + dependencies: + array-each "^1.0.1" + array-slice "^1.0.0" + for-own "^1.0.0" + isobject "^3.0.0" + object.omit@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/object.omit/-/object.omit-2.0.1.tgz#1a9c744829f39dbb858c76ca3579ae2a54ebd1fa" @@ -5327,6 +5519,12 @@ object.omit@^2.0.0: for-own "^0.1.4" is-extendable "^0.1.1" +object.pick@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/object.pick/-/object.pick-1.2.0.tgz#b5392bee9782da6d9fb7d6afaf539779f1234c2b" + dependencies: + isobject "^2.1.0" + on-finished@~2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" @@ -5349,15 +5547,21 @@ once@~1.3.0: dependencies: wrappy "1" +onetime@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/onetime/-/onetime-2.0.1.tgz#067428230fd67443b2794b22bba528b6867962d4" + dependencies: + mimic-fn "^1.0.0" + open@0.0.5: version "0.0.5" resolved "https://registry.yarnpkg.com/open/-/open-0.0.5.tgz#42c3e18ec95466b6bf0dc42f3a2945c3f0cad8fc" -openurl@1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/openurl/-/openurl-1.1.0.tgz#e2f2189d999c04823201f083f0f1a7cd8903187a" +openurl@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/openurl/-/openurl-1.1.1.tgz#3875b4b0ef7a52c156f0db41d4609dbb0f94b387" -optimist@0.6.1, optimist@^0.6.1, optimist@~0.6.0, optimist@~0.6.1: +optimist@0.6.1, optimist@^0.6.1, optimist@~0.6.0: version "0.6.1" resolved "https://registry.yarnpkg.com/optimist/-/optimist-0.6.1.tgz#da3ea74686fa21a19a111c326e90eb15a0196686" dependencies: @@ -5380,16 +5584,16 @@ optimize-js@^1.0.0: magic-string "^0.16.0" yargs "^4.8.1" -optionator@^0.5.0: - version "0.5.0" - resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.5.0.tgz#b75a8995a2d417df25b6e4e3862f50aa88651368" +optionator@^0.8.1, optionator@^0.8.2: + version "0.8.2" + resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.2.tgz#364c5e409d3f4d6301d6c0b4c05bba50180aeb64" dependencies: - deep-is "~0.1.2" - fast-levenshtein "~1.0.0" - levn "~0.2.5" - prelude-ls "~1.1.1" - type-check "~0.3.1" - wordwrap "~0.0.2" + deep-is "~0.1.3" + fast-levenshtein "~2.0.4" + levn "~0.3.0" + prelude-ls "~1.1.2" + type-check "~0.3.2" + wordwrap "~1.0.0" options@>=0.0.5: version "0.0.6" @@ -5432,46 +5636,58 @@ osenv@^0.1.4: os-homedir "^1.0.0" os-tmpdir "^1.0.0" -output-file-sync@^1.1.0: - version "1.1.2" - resolved "https://registry.yarnpkg.com/output-file-sync/-/output-file-sync-1.1.2.tgz#d0a33eefe61a205facb90092e826598d5245ce76" - dependencies: - graceful-fs "^4.1.4" - mkdirp "^0.5.1" - object-assign "^4.1.0" - "over@>= 0.0.5 < 1": version "0.0.5" resolved "https://registry.yarnpkg.com/over/-/over-0.0.5.tgz#f29852e70fd7e25f360e013a8ec44c82aedb5708" +p-limit@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-1.1.0.tgz#b07ff2d9a5d88bec806035895a2bab66a27988bc" + +p-locate@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-2.0.0.tgz#20a0103b222a70c8fd39cc2e580680f3dde5ec43" + dependencies: + p-limit "^1.1.0" + pac-proxy-agent@1: - version "1.0.0" - resolved "https://registry.yarnpkg.com/pac-proxy-agent/-/pac-proxy-agent-1.0.0.tgz#dcd5b746581367430a236e88eacfd4e5b8d068a5" + version "1.1.0" + resolved "https://registry.yarnpkg.com/pac-proxy-agent/-/pac-proxy-agent-1.1.0.tgz#34a385dfdf61d2f0ecace08858c745d3e791fd4d" dependencies: agent-base "2" debug "2" extend "3" - get-uri "1" + get-uri "2" http-proxy-agent "1" https-proxy-agent "1" - pac-resolver "~1.2.1" + pac-resolver "~2.0.0" + raw-body "2" socks-proxy-agent "2" - stream-to-buffer "0.1.0" -pac-resolver@~1.2.1: - version "1.2.6" - resolved "https://registry.yarnpkg.com/pac-resolver/-/pac-resolver-1.2.6.tgz#ed03af0c5b5933505bdd3f07f75175466d5e7cfb" +pac-resolver@~2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/pac-resolver/-/pac-resolver-2.0.0.tgz#99b88d2f193fbdeefc1c9a529c1f3260ab5277cd" dependencies: co "~3.0.6" - degenerator "~1.0.0" + degenerator "~1.0.2" + ip "1.0.1" netmask "~1.0.4" - regenerator "~0.8.13" thunkify "~2.1.1" pako@~0.2.0: version "0.2.9" resolved "https://registry.yarnpkg.com/pako/-/pako-0.2.9.tgz#f3f7522f4ef782348da8161bad9ecfd51bf83a75" +parse-asn1@^5.0.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/parse-asn1/-/parse-asn1-5.1.0.tgz#37c4f9b7ed3ab65c74817b5f2480937fbf97c712" + dependencies: + asn1.js "^4.0.0" + browserify-aes "^1.0.0" + create-hash "^1.1.0" + evp_bytestokey "^1.0.0" + pbkdf2 "^3.0.3" + parse-filepath@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/parse-filepath/-/parse-filepath-1.0.1.tgz#159d6155d43904d16c10ef698911da1e91969b73" @@ -5525,24 +5741,28 @@ path-browserify@0.0.0: version "0.0.0" resolved "https://registry.yarnpkg.com/path-browserify/-/path-browserify-0.0.0.tgz#a0b870729aae214005b7d5032ec2cbbb0fb4451a" -path-exists@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-1.0.0.tgz#d5a8998eb71ef37a74c34eb0d9eba6e878eea081" - path-exists@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-2.1.0.tgz#0feb6c64f0fc518d9a754dd5efb62c7022761f4b" dependencies: pinkie-promise "^2.0.0" +path-exists@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" + path-is-absolute@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" -path-is-inside@^1.0.1: +path-is-inside@^1.0.1, path-is-inside@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53" +path-parse@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.5.tgz#3c1adf871ea9cd6c9431b6ea2bd74a0ff055c4c1" + path-root-regex@^0.1.0: version "0.1.2" resolved "https://registry.yarnpkg.com/path-root-regex/-/path-root-regex-0.1.2.tgz#bfccdc8df5b12dc52c8b43ec38d18d72c04ba96d" @@ -5561,9 +5781,11 @@ path-type@^1.0.0: pify "^2.0.0" pinkie-promise "^2.0.0" -pathval@~0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/pathval/-/pathval-0.1.1.tgz#08f911cdca9cce5942880da7817bc0b723b66d82" +path-type@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/path-type/-/path-type-2.0.0.tgz#f012ccb8415b7096fc2daa1054c3d72389594c73" + dependencies: + pify "^2.0.0" pause-stream@0.0.11: version "0.0.11" @@ -5579,28 +5801,21 @@ pbkdf2-compat@2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/pbkdf2-compat/-/pbkdf2-compat-2.0.1.tgz#b6e0c8fa99494d94e0511575802a59a5c142f288" -pend@~1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/pend/-/pend-1.2.0.tgz#7a57eb550a6783f9115331fcf4663d5c8e007a50" +pbkdf2@^3.0.3: + version "3.0.12" + resolved "https://registry.yarnpkg.com/pbkdf2/-/pbkdf2-3.0.12.tgz#be36785c5067ea48d806ff923288c5f750b6b8a2" + dependencies: + create-hash "^1.1.2" + create-hmac "^1.1.4" + ripemd160 "^2.0.1" + safe-buffer "^5.0.1" + sha.js "^2.4.8" performance-now@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-0.2.0.tgz#33ef30c5c77d4ea21c5a53869d91b56d8f2555e5" -phantomjs@^1.9.18: - version "1.9.20" - resolved "https://registry.yarnpkg.com/phantomjs/-/phantomjs-1.9.20.tgz#4424aca20e14d255c0b0889af6f6b8973da10e0d" - dependencies: - extract-zip "~1.5.0" - fs-extra "~0.26.4" - hasha "^2.2.0" - kew "~0.7.0" - progress "~1.1.8" - request "~2.67.0" - request-progress "~2.0.1" - which "~1.2.2" - -pify@^2.0.0: +pify@^2.0.0, pify@^2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" @@ -5620,21 +5835,17 @@ pkg-dir@^1.0.0: dependencies: find-up "^1.0.0" -pkginfo@0.3.x: - version "0.3.1" - resolved "https://registry.yarnpkg.com/pkginfo/-/pkginfo-0.3.1.tgz#5b29f6a81f70717142e09e765bbeab97b4f81e21" - -pkginfo@0.x.x: - version "0.4.0" - resolved "https://registry.yarnpkg.com/pkginfo/-/pkginfo-0.4.0.tgz#349dbb7ffd38081fcadc0853df687f0c7744cd65" - -plur@^2.1.0: - version "2.1.2" - resolved "https://registry.yarnpkg.com/plur/-/plur-2.1.2.tgz#7482452c1a0f508e3e344eaec312c91c29dc655a" +pkg-dir@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-2.0.0.tgz#f6d5d1109e19d63edf428e0bd57e12777615334b" dependencies: - irregular-plurals "^1.0.0" + find-up "^2.1.0" + +pluralize@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/pluralize/-/pluralize-4.0.0.tgz#59b708c1c0190a2f692f1c7618c446b052fd1762" -prelude-ls@~1.1.0, prelude-ls@~1.1.1, prelude-ls@~1.1.2: +prelude-ls@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" @@ -5646,7 +5857,7 @@ pretty-hrtime@^1.0.0: version "1.0.3" resolved "https://registry.yarnpkg.com/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz#b7e3ea42435a4c9b2759d99e0f201eb195802ee1" -private@^0.1.6, private@~0.1.5: +private@^0.1.6: version "0.1.7" resolved "https://registry.yarnpkg.com/private/-/private-0.1.7.tgz#68ce5e8a1ef0a23bb570cc28537b5332aba63ef1" @@ -5655,33 +5866,23 @@ process-nextick-args@^1.0.6, process-nextick-args@~1.0.6: resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-1.0.7.tgz#150e20b756590ad3f91093f25a4f2ad8bff30ba3" process@^0.11.0: - version "0.11.9" - resolved "https://registry.yarnpkg.com/process/-/process-0.11.9.tgz#7bd5ad21aa6253e7da8682264f1e11d11c0318c1" + version "0.11.10" + resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182" -progress@~1.1.8: - version "1.1.8" - resolved "https://registry.yarnpkg.com/progress/-/progress-1.1.8.tgz#e260c78f6161cdd9b0e56cc3e0a85de17c7a57be" +progress@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.0.tgz#8a1be366bf8fc23db2bd23f10c6fe920b4389d1f" promise.prototype.finally@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/promise.prototype.finally/-/promise.prototype.finally-1.0.1.tgz#91182f91c92486995740fa05e0da942ac986befa" "promise@>=3.2 <8": - version "7.1.1" - resolved "https://registry.yarnpkg.com/promise/-/promise-7.1.1.tgz#489654c692616b8aa55b0724fa809bb7db49c5bf" + version "7.3.1" + resolved "https://registry.yarnpkg.com/promise/-/promise-7.3.1.tgz#064b72602b18f90f29192b8b1bc418ffd1ebd3bf" dependencies: asap "~2.0.3" -prompt@~0.2.14: - version "0.2.14" - resolved "https://registry.yarnpkg.com/prompt/-/prompt-0.2.14.tgz#57754f64f543fd7b0845707c818ece618f05ffdc" - dependencies: - pkginfo "0.x.x" - read "1.0.x" - revalidator "0.1.x" - utile "0.2.x" - winston "0.8.x" - proxy-agent@2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/proxy-agent/-/proxy-agent-2.0.0.tgz#57eb5347aa805d74ec681cb25649dba39c933499" @@ -5696,8 +5897,8 @@ proxy-agent@2.0.0: socks-proxy-agent "2" proxyquire@^1.7.10: - version "1.7.11" - resolved "https://registry.yarnpkg.com/proxyquire/-/proxyquire-1.7.11.tgz#13b494eb1e71fb21cc3ebe3699e637d3bec1af9e" + version "1.8.0" + resolved "https://registry.yarnpkg.com/proxyquire/-/proxyquire-1.8.0.tgz#02d514a5bed986f04cbb2093af16741535f79edc" dependencies: fill-keys "^1.0.2" module-not-found-error "^1.0.0" @@ -5707,6 +5908,16 @@ prr@~0.0.0: version "0.0.0" resolved "https://registry.yarnpkg.com/prr/-/prr-0.0.0.tgz#1a84b85908325501411853d0081ee3fa86e2926a" +public-encrypt@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/public-encrypt/-/public-encrypt-4.0.0.tgz#39f699f3a46560dd5ebacbca693caf7c65c18cc6" + dependencies: + bn.js "^4.1.0" + browserify-rsa "^4.0.0" + create-hash "^1.1.0" + parse-asn1 "^5.0.0" + randombytes "^2.0.1" + "pullstream@>= 0.4.1 < 1": version "0.4.1" resolved "https://registry.yarnpkg.com/pullstream/-/pullstream-0.4.1.tgz#d6fb3bf5aed697e831150eb1002c25a3f8ae1314" @@ -5724,18 +5935,22 @@ punycode@^1.2.4, punycode@^1.4.1: version "1.4.1" resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" -q@1.4.1, q@^1.1.2, q@~1.4.1: +q@1.4.1: version "1.4.1" resolved "https://registry.yarnpkg.com/q/-/q-1.4.1.tgz#55705bcd93c5f3673530c2c2cbc0c2b3addc286e" -q@~0.9.6: - version "0.9.7" - resolved "https://registry.yarnpkg.com/q/-/q-0.9.7.tgz#4de2e6cb3b29088c9e4cbc03bf9d42fb96ce2f75" +q@^1.4.1, q@~1.5.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/q/-/q-1.5.0.tgz#dd01bac9d06d30e6f219aecb8253ee9ebdc308f1" q@~1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/q/-/q-1.3.0.tgz#850d79f8cb831d92e103b46483e4e35d34640050" +qjobs@^1.1.4: + version "1.1.5" + resolved "https://registry.yarnpkg.com/qjobs/-/qjobs-1.1.5.tgz#659de9f2cf8dcc27a1481276f205377272382e73" + qs@4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/qs/-/qs-4.0.0.tgz#c31d9b74ec27df75e543a86c78728ed8d4623607" @@ -5752,18 +5967,10 @@ qs@~2.3.1: version "2.3.3" resolved "https://registry.yarnpkg.com/qs/-/qs-2.3.3.tgz#e9e85adbe75da0bbe4c8e0476a086290f863b404" -qs@~2.4.0: - version "2.4.2" - resolved "https://registry.yarnpkg.com/qs/-/qs-2.4.2.tgz#f7ce788e5777df0b5010da7f7c4e73ba32470f5a" - qs@~5.1.0: version "5.1.0" resolved "https://registry.yarnpkg.com/qs/-/qs-5.1.0.tgz#4d932e5c7ea411cca76a312d39a606200fd50cd9" -qs@~5.2.0: - version "5.2.1" - resolved "https://registry.yarnpkg.com/qs/-/qs-5.2.1.tgz#801fee030e0b9450d6385adc48a4cc55b44aedfc" - qs@~6.3.0: version "6.3.2" resolved "https://registry.yarnpkg.com/qs/-/qs-6.3.2.tgz#e75bd5f6e268122a2a0e0bda630b2550c166502c" @@ -5776,22 +5983,32 @@ querystring@0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620" -querystringify@0.0.3, querystringify@0.0.x: +querystringify@0.0.3: version "0.0.3" resolved "https://registry.yarnpkg.com/querystringify/-/querystringify-0.0.3.tgz#0c9d36fbf8c7a4f71eb370857763577a63335be7" +querystringify@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/querystringify/-/querystringify-1.0.0.tgz#6286242112c5b712fa654e526652bf6a13ff05cb" + random-bytes@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/random-bytes/-/random-bytes-1.0.0.tgz#4f68a1dc0ae58bd3fb95848c30324db75d64360b" randomatic@^1.1.3: - version "1.1.6" - resolved "https://registry.yarnpkg.com/randomatic/-/randomatic-1.1.6.tgz#110dcabff397e9dcff7c0789ccc0a49adf1ec5bb" + version "1.1.7" + resolved "https://registry.yarnpkg.com/randomatic/-/randomatic-1.1.7.tgz#c7abe9cc8b87c0baa876b19fde83fd464797e38c" dependencies: - is-number "^2.0.2" - kind-of "^3.0.2" + is-number "^3.0.0" + kind-of "^4.0.0" + +randombytes@^2.0.0, randombytes@^2.0.1: + version "2.0.5" + resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.0.5.tgz#dc009a246b8d09a177b4b7a0ae77bc570f4b1b79" + dependencies: + safe-buffer "^5.1.0" -range-parser@^1.0.3: +range-parser@^1.0.3, range-parser@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.0.tgz#f49be6b487894ddc40dcc94a322f611092e00d5e" @@ -5799,20 +6016,20 @@ range-parser@~1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.0.3.tgz#6872823535c692e2c2a0103826afd82c2e0ff175" -raw-body@~2.1.2, raw-body@~2.1.5: - version "2.1.7" - resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.1.7.tgz#adfeace2e4fb3098058014d08c072dcc59758774" +raw-body@2, raw-body@~2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.2.0.tgz#994976cf6a5096a41162840492f0bdc5d6e7fb96" dependencies: bytes "2.4.0" - iconv-lite "0.4.13" + iconv-lite "0.4.15" unpipe "1.0.0" -raw-body@~2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.2.0.tgz#994976cf6a5096a41162840492f0bdc5d6e7fb96" +raw-body@~2.1.2, raw-body@~2.1.5: + version "2.1.7" + resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.1.7.tgz#adfeace2e4fb3098058014d08c072dcc59758774" dependencies: bytes "2.4.0" - iconv-lite "0.4.15" + iconv-lite "0.4.13" unpipe "1.0.0" rc@^1.1.7: @@ -5824,19 +6041,6 @@ rc@^1.1.7: minimist "^1.2.0" strip-json-comments "~2.0.1" -rcfinder@~0.1.6: - version "0.1.9" - resolved "https://registry.yarnpkg.com/rcfinder/-/rcfinder-0.1.9.tgz#f3e80f387ddf9ae80ae30a4100329642eae81115" - dependencies: - lodash.clonedeep "^4.3.2" - -rcloader@0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/rcloader/-/rcloader-0.1.2.tgz#a0963a6437d09ef8cb92d932d2dad497b0d1736c" - dependencies: - lodash "~2.4.1" - rcfinder "~0.1.6" - read-pkg-up@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-1.0.1.tgz#9d63c13276c065918d57f002a57f40a1b643fb02" @@ -5844,6 +6048,13 @@ read-pkg-up@^1.0.1: find-up "^1.0.0" read-pkg "^1.0.0" +read-pkg-up@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-2.0.0.tgz#6b72a8048984e0c41e79510fd5e9fa99b3b549be" + dependencies: + find-up "^2.0.0" + read-pkg "^2.0.0" + read-pkg@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-1.1.0.tgz#f5ffaa5ecd29cb31c0474bca7d756b6bb29e3f28" @@ -5852,13 +6063,15 @@ read-pkg@^1.0.0: normalize-package-data "^2.3.2" path-type "^1.0.0" -read@1.0.x: - version "1.0.7" - resolved "https://registry.yarnpkg.com/read/-/read-1.0.7.tgz#b3da19bd052431a97671d44a42634adf710b40c4" +read-pkg@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-2.0.0.tgz#8ef1c0623c6a6db0dc6713c4bfac46332b2368f8" dependencies: - mute-stream "~0.0.4" + load-json-file "^2.0.0" + normalize-package-data "^2.3.2" + path-type "^2.0.0" -readable-stream@1.1, readable-stream@1.1.x, readable-stream@~1.1.8, readable-stream@~1.1.9: +readable-stream@1.1.x, readable-stream@~1.1.8, readable-stream@~1.1.9: version "1.1.14" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.1.14.tgz#7cf4c54ef648e3813084c636dd2079e166c081d9" dependencies: @@ -5867,16 +6080,16 @@ readable-stream@1.1, readable-stream@1.1.x, readable-stream@~1.1.8, readable-str isarray "0.0.1" string_decoder "~0.10.x" -readable-stream@2, "readable-stream@^2.0.0 || ^1.1.13", readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.4, readable-stream@^2.0.5, readable-stream@^2.1.4, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@^2.2.6: - version "2.2.8" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.2.8.tgz#ad28b686f3554c73d39bc32347fa058356624705" +readable-stream@2, readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.5, readable-stream@^2.0.6, readable-stream@^2.1.4, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@^2.2.6: + version "2.3.3" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.3.tgz#368f2512d79f9d46fdfc71349ae7878bbc1eb95c" dependencies: - buffer-shims "~1.0.0" core-util-is "~1.0.0" - inherits "~2.0.1" + inherits "~2.0.3" isarray "~1.0.0" process-nextick-args "~1.0.6" - string_decoder "~1.0.0" + safe-buffer "~5.1.1" + string_decoder "~1.0.3" util-deprecate "~1.0.1" "readable-stream@>=1.0.33-1 <1.1.0-0", readable-stream@~1.0.0, readable-stream@~1.0.17, readable-stream@~1.0.2, readable-stream@~1.0.24, readable-stream@~1.0.26, readable-stream@~1.0.31, readable-stream@~1.0.33: @@ -5888,17 +6101,6 @@ readable-stream@2, "readable-stream@^2.0.0 || ^1.1.13", readable-stream@^2.0.1, isarray "0.0.1" string_decoder "~0.10.x" -readable-stream@~2.0.0, readable-stream@~2.0.5: - version "2.0.6" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.0.6.tgz#8f90341e68a53ccc928788dacfcd11b36eb9b78e" - dependencies: - core-util-is "~1.0.0" - inherits "~2.0.1" - isarray "~1.0.0" - process-nextick-args "~1.0.6" - string_decoder "~0.10.x" - util-deprecate "~1.0.1" - readdirp@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-2.1.0.tgz#4ed0ad060df3073300c48440373f72d1cc642d78" @@ -5915,24 +6117,6 @@ readline2@^0.1.1: mute-stream "0.0.4" strip-ansi "^2.0.1" -recast@0.10.33, recast@^0.10.10: - version "0.10.33" - resolved "https://registry.yarnpkg.com/recast/-/recast-0.10.33.tgz#942808f7aa016f1fa7142c461d7e5704aaa8d697" - dependencies: - ast-types "0.8.12" - esprima-fb "~15001.1001.0-dev-harmony-fb" - private "~0.1.5" - source-map "~0.5.0" - -recast@^0.11.17: - version "0.11.23" - resolved "https://registry.yarnpkg.com/recast/-/recast-0.11.23.tgz#451fd3004ab1e4df9b4e4b66376b2a21912462d3" - dependencies: - ast-types "0.9.6" - esprima "~3.1.0" - private "~0.1.5" - source-map "~0.5.0" - rechoir@^0.6.2: version "0.6.2" resolved "https://registry.yarnpkg.com/rechoir/-/rechoir-0.6.2.tgz#85204b54dba82d5742e28c96756ef43af50e3384" @@ -5971,8 +6155,8 @@ regenerate@^1.2.1: resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.3.2.tgz#d1941c67bad437e1be76433add5b385f95b19260" regenerator-runtime@^0.10.0: - version "0.10.3" - resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.10.3.tgz#8c4367a904b51ea62a908ac310bf99ff90a82a3e" + version "0.10.5" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.10.5.tgz#336c3efc1220adcedda2c9fab67b5a7955a33658" regenerator-transform@0.9.11: version "0.9.11" @@ -5982,17 +6166,6 @@ regenerator-transform@0.9.11: babel-types "^6.19.0" private "^0.1.6" -regenerator@0.8.40, regenerator@~0.8.13: - version "0.8.40" - resolved "https://registry.yarnpkg.com/regenerator/-/regenerator-0.8.40.tgz#a0e457c58ebdbae575c9f8cd75127e93756435d8" - dependencies: - commoner "~0.10.3" - defs "~1.1.0" - esprima-fb "~15001.1001.0-dev-harmony-fb" - private "~0.1.5" - recast "0.10.33" - through "~2.3.8" - regex-cache@^0.4.2: version "0.4.3" resolved "https://registry.yarnpkg.com/regex-cache/-/regex-cache-0.4.3.tgz#9b1a6c35d4d0dfcef5711ae651e8e9d3d7114145" @@ -6008,16 +6181,6 @@ regexpu-core@^2.0.0: regjsgen "^0.2.0" regjsparser "^0.1.4" -regexpu@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/regexpu/-/regexpu-1.3.0.tgz#e534dc991a9e5846050c98de6d7dd4a55c9ea16d" - dependencies: - esprima "^2.6.0" - recast "^0.10.10" - regenerate "^1.2.1" - regjsgen "^0.2.0" - regjsparser "^0.1.4" - regjsgen@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/regjsgen/-/regjsgen-0.2.0.tgz#6c016adeac554f75823fe37ac05b92d5a4edb1f7" @@ -6029,8 +6192,8 @@ regjsparser@^0.1.4: jsesc "~0.5.0" remove-trailing-separator@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.0.1.tgz#615ebb96af559552d4bf4057c8436d486ab63cc4" + version "1.0.2" + resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.0.2.tgz#69b062d978727ad14dc6b56ba4ab772fd8d70511" repeat-element@^1.1.2: version "1.1.2" @@ -6044,12 +6207,6 @@ repeat-string@^1.5.2: version "1.6.1" resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" -repeating@^1.1.0, repeating@^1.1.2: - version "1.1.3" - resolved "https://registry.yarnpkg.com/repeating/-/repeating-1.1.3.tgz#3d4114218877537494f97f77f9785fab810fa4ac" - dependencies: - is-finite "^1.0.0" - repeating@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/repeating/-/repeating-2.0.1.tgz#5214c53a926d3552707527fbab415dbc08d06dda" @@ -6070,7 +6227,7 @@ replacestream@0.1.3: dependencies: through "~2.3.4" -req-then@^0.5.1: +req-then@0.5.1: version "0.5.1" resolved "https://registry.yarnpkg.com/req-then/-/req-then-0.5.1.tgz#31c6e0b56f4ddd2acd6de0ba1bcea77b6079dfdf" dependencies: @@ -6080,12 +6237,6 @@ req-then@^0.5.1: lodash.pick "^4.4.0" typical "^2.6.0" -request-progress@~2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/request-progress/-/request-progress-2.0.1.tgz#5d36bb57961c673aa5b788dbc8141fdf23b44e08" - dependencies: - throttleit "^1.0.0" - request@2.49.0: version "2.49.0" resolved "https://registry.yarnpkg.com/request/-/request-2.49.0.tgz#0d4f6348dc3348059b553e4db60fd2478de662a7" @@ -6107,31 +6258,6 @@ request@2.49.0: tough-cookie ">=0.12.0" tunnel-agent "~0.4.0" -request@2.78.0: - version "2.78.0" - resolved "https://registry.yarnpkg.com/request/-/request-2.78.0.tgz#e1c8dec346e1c81923b24acdb337f11decabe9cc" - dependencies: - aws-sign2 "~0.6.0" - aws4 "^1.2.1" - caseless "~0.11.0" - combined-stream "~1.0.5" - extend "~3.0.0" - forever-agent "~0.6.1" - form-data "~2.1.1" - har-validator "~2.0.6" - hawk "~3.1.3" - http-signature "~1.1.0" - is-typedarray "~1.0.0" - isstream "~0.1.2" - json-stringify-safe "~5.0.1" - mime-types "~2.1.7" - node-uuid "~1.4.7" - oauth-sign "~0.8.1" - qs "~6.3.0" - stringstream "~0.0.4" - tough-cookie "~2.3.0" - tunnel-agent "~0.4.1" - request@2.79.0: version "2.79.0" resolved "https://registry.yarnpkg.com/request/-/request-2.79.0.tgz#4dfe5bf6be8b8cdc37fcf93e04b65577722710de" @@ -6157,7 +6283,7 @@ request@2.79.0: tunnel-agent "~0.4.1" uuid "^3.0.0" -request@^2.81.0: +request@2.81.0, request@^2.81.0: version "2.81.0" resolved "https://registry.yarnpkg.com/request/-/request-2.81.0.tgz#c6928946a0e06c5f8d6f8a9333469ffda46298a0" dependencies: @@ -6184,54 +6310,6 @@ request@^2.81.0: tunnel-agent "^0.6.0" uuid "^3.0.0" -request@~2.55.0: - version "2.55.0" - resolved "https://registry.yarnpkg.com/request/-/request-2.55.0.tgz#d75c1cdf679d76bb100f9bffe1fe551b5c24e93d" - dependencies: - aws-sign2 "~0.5.0" - bl "~0.9.0" - caseless "~0.9.0" - combined-stream "~0.0.5" - forever-agent "~0.6.0" - form-data "~0.2.0" - har-validator "^1.4.0" - hawk "~2.3.0" - http-signature "~0.10.0" - isstream "~0.1.1" - json-stringify-safe "~5.0.0" - mime-types "~2.0.1" - node-uuid "~1.4.0" - oauth-sign "~0.6.0" - qs "~2.4.0" - stringstream "~0.0.4" - tough-cookie ">=0.12.0" - tunnel-agent "~0.4.0" - -request@~2.67.0: - version "2.67.0" - resolved "https://registry.yarnpkg.com/request/-/request-2.67.0.tgz#8af74780e2bf11ea0ae9aa965c11f11afd272742" - dependencies: - aws-sign2 "~0.6.0" - bl "~1.0.0" - caseless "~0.11.0" - combined-stream "~1.0.5" - extend "~3.0.0" - forever-agent "~0.6.1" - form-data "~1.0.0-rc3" - har-validator "~2.0.2" - hawk "~3.1.0" - http-signature "~1.1.0" - is-typedarray "~1.0.0" - isstream "~0.1.2" - json-stringify-safe "~5.0.1" - mime-types "~2.1.7" - node-uuid "~1.4.7" - oauth-sign "~0.8.0" - qs "~5.2.0" - stringstream "~0.0.4" - tough-cookie "~2.2.0" - tunnel-agent "~0.4.1" - require-directory@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" @@ -6240,6 +6318,13 @@ require-main-filename@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-1.0.1.tgz#97f717b69d48784f5f526a6c5aa8ffdda055a4d1" +require-uncached@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/require-uncached/-/require-uncached-1.0.3.tgz#4e0d56d6c9662fd31e43011c4b95aa49955421d3" + dependencies: + caller-path "^0.1.0" + resolve-from "^1.0.0" + requirejs@^2.1.20: version "2.3.3" resolved "https://registry.yarnpkg.com/requirejs/-/requirejs-2.3.3.tgz#aa59fd3a0287eaf407959a138228044b5dd6a6a3" @@ -6254,10 +6339,6 @@ requizzle@~0.2.1: dependencies: underscore "~1.6.0" -reserved-words@^0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/reserved-words/-/reserved-words-0.1.1.tgz#6f7c15e5e5614c50da961630da46addc87c0cef2" - resolve-dir@^0.1.0: version "0.1.1" resolved "https://registry.yarnpkg.com/resolve-dir/-/resolve-dir-0.1.1.tgz#b219259a5602fac5c5c496ad894a6e8cc430261e" @@ -6273,10 +6354,16 @@ resolve-url@~0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a" -resolve@1.1.x, resolve@^1.1.6, resolve@^1.1.7, resolve@~1.1.7: +resolve@1.1.x, resolve@~1.1.7: version "1.1.7" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.1.7.tgz#203114d82ad2c5ed9e8e0411b3932875e889e97b" +resolve@^1.1.6, resolve@^1.1.7, resolve@^1.2.0, resolve@^1.3.3: + version "1.3.3" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.3.3.tgz#655907c3469a8680dc2de3a275a8fdd69691f0e5" + dependencies: + path-parse "^1.0.5" + response-time@~2.3.1: version "2.3.2" resolved "https://registry.yarnpkg.com/response-time/-/response-time-2.3.2.tgz#ffa71bab952d62f7c1d49b7434355fbc68dffc5a" @@ -6284,9 +6371,12 @@ response-time@~2.3.1: depd "~1.1.0" on-headers "~1.0.1" -revalidator@0.1.x: - version "0.1.8" - resolved "https://registry.yarnpkg.com/revalidator/-/revalidator-0.1.8.tgz#fece61bfa0c1b52a206bd6b18198184bdd523a3b" +restore-cursor@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-2.0.0.tgz#9f7ee287f82fd326d4fd162923d62129eee0dfaf" + dependencies: + onetime "^2.0.0" + signal-exit "^3.0.2" rewire@2.5.2: version "2.5.2" @@ -6302,17 +6392,19 @@ right-align@^0.1.1: dependencies: align-text "^0.1.1" -rimraf@2, rimraf@2.x.x, rimraf@^2.2.8, rimraf@^2.3.3, rimraf@^2.5.1, rimraf@^2.6.1: +rimraf@2, rimraf@^2.2.8, rimraf@^2.5.1, rimraf@^2.6.0, rimraf@^2.6.1: version "2.6.1" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.1.tgz#c2338ec643df7a1b7fe5c54fa86f57428a55f33d" dependencies: glob "^7.0.5" -rimraf@2.2.6: - version "2.2.6" - resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.2.6.tgz#c59597569b14d956ad29cacc42bdddf5f0ea4f4c" +rimraf@2.4.3: + version "2.4.3" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.4.3.tgz#e5b51c9437a4c582adb955e9f28cf8d945e272af" + dependencies: + glob "^5.0.14" -rimraf@~2.2.0, rimraf@~2.2.6: +rimraf@~2.2.0: version "2.2.8" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.2.8.tgz#e439be2aaee327321952730f99a8929e4fc50582" @@ -6320,34 +6412,60 @@ ripemd160@0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/ripemd160/-/ripemd160-0.2.0.tgz#2bf198bde167cacfa51c0a928e84b68bbe171fce" +ripemd160@^2.0.0, ripemd160@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/ripemd160/-/ripemd160-2.0.1.tgz#0f4584295c53a3628af7e6d79aca21ce57d1c6e7" + dependencies: + hash-base "^2.0.0" + inherits "^2.0.1" + rndm@1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/rndm/-/rndm-1.2.0.tgz#f33fe9cfb52bbfd520aa18323bc65db110a1b76c" +run-async@^2.2.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.3.0.tgz#0371ab4ae0bdd720d4166d7dfda64ff7a445a6c0" + dependencies: + is-promise "^2.1.0" + +rx-lite-aggregates@^4.0.8: + version "4.0.8" + resolved "https://registry.yarnpkg.com/rx-lite-aggregates/-/rx-lite-aggregates-4.0.8.tgz#753b87a89a11c95467c4ac1626c4efc4e05c67be" + dependencies: + rx-lite "*" + +rx-lite@*, rx-lite@^4.0.8: + version "4.0.8" + resolved "https://registry.yarnpkg.com/rx-lite/-/rx-lite-4.0.8.tgz#0b1e11af8bc44836f04a6407e92da42467b79444" + rx@^2.4.3: version "2.5.3" resolved "https://registry.yarnpkg.com/rx/-/rx-2.5.3.tgz#21adc7d80f02002af50dae97fd9dbf248755f566" -safe-buffer@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.0.1.tgz#d263ca54696cd8a306b5ca6551e92de57918fbe7" +safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@~5.1.0, safe-buffer@~5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.1.tgz#893312af69b2123def71f57889001671eeb2c853" samsam@1.1.2, samsam@~1.1: version "1.1.2" resolved "https://registry.yarnpkg.com/samsam/-/samsam-1.1.2.tgz#bec11fdc83a9fda063401210e40176c3024d1567" -sauce-connect-launcher@~0.11.1: - version "0.11.1" - resolved "https://registry.yarnpkg.com/sauce-connect-launcher/-/sauce-connect-launcher-0.11.1.tgz#65f51d8891249fdabaaf17599734de1902476129" +sauce-connect-launcher@^0.17.0: + version "0.17.0" + resolved "https://registry.yarnpkg.com/sauce-connect-launcher/-/sauce-connect-launcher-0.17.0.tgz#908d9311ecaf17dd9b4647a1435fd4a2072e80ce" dependencies: adm-zip "~0.4.3" - async "0.9.0" - lodash "3.5.0" - rimraf "2.2.6" + async "1.4.0" + https-proxy-agent "~1.0.0" + lodash "3.10.1" + rimraf "2.4.3" -saucelabs@~0.1.0: - version "0.1.1" - resolved "https://registry.yarnpkg.com/saucelabs/-/saucelabs-0.1.1.tgz#5e0ea1cf3d735d6ea15fde94b5bda6bc15d2c06d" +saucelabs@^1.3.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/saucelabs/-/saucelabs-1.4.0.tgz#b934a9af9da2874b3f40aae1fcde50a4466f5f38" + dependencies: + https-proxy-agent "^1.0.0" "semver@2 || 3 || 4 || 5", semver@5.3.0, semver@^5.3.0: version "5.3.0" @@ -6431,29 +6549,19 @@ sha.js@2.2.6: version "2.2.6" resolved "https://registry.yarnpkg.com/sha.js/-/sha.js-2.2.6.tgz#17ddeddc5f722fb66501658895461977867315ba" -shebang-regex@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3" - -shelljs@0.3.x: - version "0.3.0" - resolved "https://registry.yarnpkg.com/shelljs/-/shelljs-0.3.0.tgz#3596e6307a781544f591f37da618360f31db57b1" +sha.js@^2.4.0, sha.js@^2.4.8: + version "2.4.8" + resolved "https://registry.yarnpkg.com/sha.js/-/sha.js-2.4.8.tgz#37068c2c476b6baf402d14a49c67f597921f634f" + dependencies: + inherits "^2.0.1" sigmund@~1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/sigmund/-/sigmund-1.0.1.tgz#3ff21f198cad2175f9f3b781853fd94d0d19b590" -signal-exit@^3.0.0: +signal-exit@^3.0.0, signal-exit@^3.0.2: version "3.0.2" - resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d" - -simple-fmt@~0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/simple-fmt/-/simple-fmt-0.1.0.tgz#191bf566a59e6530482cb25ab53b4a8dc85c3a6b" - -simple-is@~0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/simple-is/-/simple-is-0.2.0.tgz#2abb75aade39deb5cc815ce10e6191164850baf0" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d" sinon@^1.12.1: version "1.17.7" @@ -6468,6 +6576,10 @@ slash@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/slash/-/slash-1.0.0.tgz#c41f2f6c39fc16d1cd17ad4b5d896114ae470d55" +slice-ansi@0.0.4: + version "0.0.4" + resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-0.0.4.tgz#edbf8903f66f7ce2f8eafd6ceed65e264c831b35" + "slice-stream@>= 1.0.0 < 2": version "1.0.0" resolved "https://registry.yarnpkg.com/slice-stream/-/slice-stream-1.0.0.tgz#5b33bd66f013b1a7f86460b03d463dec39ad3ea0" @@ -6522,7 +6634,7 @@ socket.io-parser@2.3.1: isarray "0.0.1" json3 "3.3.2" -socket.io@^1.4.5: +socket.io@1.7.3: version "1.7.3" resolved "https://registry.yarnpkg.com/socket.io/-/socket.io-1.7.3.tgz#b8af9caba00949e568e369f1327ea9be9ea2461b" dependencies: @@ -6535,8 +6647,8 @@ socket.io@^1.4.5: socket.io-parser "2.3.1" socks-proxy-agent@2: - version "2.0.0" - resolved "https://registry.yarnpkg.com/socks-proxy-agent/-/socks-proxy-agent-2.0.0.tgz#c674842d70410fb28ae1e92e6135a927854bc275" + version "2.1.1" + resolved "https://registry.yarnpkg.com/socks-proxy-agent/-/socks-proxy-agent-2.1.1.tgz#86ebb07193258637870e13b7bd99f26c663df3d3" dependencies: agent-base "2" extend "3" @@ -6550,12 +6662,16 @@ socks@~1.1.5: smart-buffer "^1.0.13" sort-array@^1.0.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/sort-array/-/sort-array-1.1.1.tgz#9032f6f0be284eecb12af98a3db02612828a66d1" + version "1.1.2" + resolved "https://registry.yarnpkg.com/sort-array/-/sort-array-1.1.2.tgz#b88986053c0170a7f9de63f18a49ec79c24c3e64" dependencies: - array-back "^1.0.3" - object-get "^2.0.4" - typical "^2.4.2" + array-back "^1.0.4" + object-get "^2.1.0" + typical "^2.6.0" + +source-list-map@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/source-list-map/-/source-list-map-2.0.0.tgz#aaa47403f7b245a92fbc97ea08f250d6087ed085" source-list-map@~0.1.7: version "0.1.8" @@ -6570,15 +6686,9 @@ source-map-resolve@^0.3.0: source-map-url "~0.3.0" urix "~0.1.0" -source-map-support@^0.2.10: - version "0.2.10" - resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.2.10.tgz#ea5a3900a1c1cb25096a0ae8cc5c2b4b10ded3dc" - dependencies: - source-map "0.1.32" - source-map-support@^0.4.2: - version "0.4.14" - resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.4.14.tgz#9d4463772598b86271b4f523f6c1f4e02a7d6aef" + version "0.4.15" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.4.15.tgz#03202df65c06d2bd8c7ec2362a193056fef8d3b1" dependencies: source-map "^0.5.6" @@ -6586,11 +6696,9 @@ source-map-url@~0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.3.0.tgz#7ecaf13b57bcd09da8a40c5d269db33799d4aaf9" -source-map@0.1.32: - version "0.1.32" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.1.32.tgz#c8b6c167797ba4740a8ea33252162ff08591b266" - dependencies: - amdefine ">=0.0.4" +source-map@0.X, source-map@^0.5.0, source-map@^0.5.1, source-map@^0.5.3, source-map@^0.5.6, source-map@~0.5.1, source-map@~0.5.3: + version "0.5.6" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.6.tgz#75ce38f52bf0733c5a7f0c118d81334a2bb5f412" source-map@^0.1.38, source-map@^0.1.40, source-map@^0.1.41, source-map@~0.1.38, source-map@~0.1.7: version "0.1.43" @@ -6604,10 +6712,6 @@ source-map@^0.4.4, source-map@~0.4.1: dependencies: amdefine ">=0.0.4" -source-map@^0.5.0, source-map@^0.5.1, source-map@^0.5.3, source-map@^0.5.6, source-map@~0.5.0, source-map@~0.5.1: - version "0.5.6" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.6.tgz#75ce38f52bf0733c5a7f0c118d81334a2bb5f412" - source-map@~0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.2.0.tgz#dab73fbcfc2ba819b4de03bd6f6eaa48164b3f9d" @@ -6644,13 +6748,13 @@ split@0.3: dependencies: through "2" -sprintf-js@~1.0.2: +sprintf-js@^1.0.3, sprintf-js@~1.0.2: version "1.0.3" resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" sshpk@^1.7.0: - version "1.11.0" - resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.11.0.tgz#2d8d5ebb4a6fab28ffba37fa62a90f4a3ea59d77" + version "1.13.1" + resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.13.1.tgz#512df6da6287144316dc4c18fe1cf1d940739be3" dependencies: asn1 "~0.2.3" assert-plus "^1.0.0" @@ -6659,18 +6763,9 @@ sshpk@^1.7.0: optionalDependencies: bcrypt-pbkdf "^1.0.0" ecc-jsbn "~0.1.1" - jodid25519 "^1.0.0" jsbn "~0.1.0" tweetnacl "~0.14.0" -stable@~0.1.3: - version "0.1.6" - resolved "https://registry.yarnpkg.com/stable/-/stable-0.1.6.tgz#910f5d2aed7b520c6e777499c1f32e139fdecb10" - -stack-trace@0.0.x: - version "0.0.9" - resolved "https://registry.yarnpkg.com/stack-trace/-/stack-trace-0.0.9.tgz#a8f6eaeca90674c333e7c43953f275b451510695" - statuses@1, "statuses@>= 1.3.1 < 2", statuses@~1.3.1: version "1.3.1" resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.3.1.tgz#faf51b9eb74aaef3b3acf4ad5f61abf24cb7b93e" @@ -6716,8 +6811,8 @@ stream-handlebars@~0.1.6: object-tools "^1.2.1" stream-http@^2.3.1: - version "2.7.0" - resolved "https://registry.yarnpkg.com/stream-http/-/stream-http-2.7.0.tgz#cec1f4e3b494bc4a81b451808970f8b20b4ed5f6" + version "2.7.2" + resolved "https://registry.yarnpkg.com/stream-http/-/stream-http-2.7.2.tgz#40a050ec8dc3b53b33d9909415c02c0bf1abfbad" dependencies: builtin-status-codes "^3.0.0" inherits "^2.0.1" @@ -6725,38 +6820,27 @@ stream-http@^2.3.1: to-arraybuffer "^1.0.0" xtend "^4.0.0" -stream-to-buffer@0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/stream-to-buffer/-/stream-to-buffer-0.1.0.tgz#26799d903ab2025c9bd550ac47171b00f8dd80a9" - dependencies: - stream-to "~0.2.0" - -stream-to@~0.2.0: - version "0.2.2" - resolved "https://registry.yarnpkg.com/stream-to/-/stream-to-0.2.2.tgz#84306098d85fdb990b9fa300b1b3ccf55e8ef01d" +stream-shift@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/stream-shift/-/stream-shift-1.0.0.tgz#d5c752825e5367e786f78e18e445ea223a155952" -stream-via@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/stream-via/-/stream-via-1.0.3.tgz#cebd32a5a59d74b3b68e3404942e867184ad4ac9" +stream-via@^1.0.3, stream-via@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/stream-via/-/stream-via-1.0.4.tgz#8dccbb0ac909328eb8bc8e2a4bd3934afdaf606c" stream-via@~0.1.0: version "0.1.1" resolved "https://registry.yarnpkg.com/stream-via/-/stream-via-0.1.1.tgz#0cee5df9c959fb1d3f4eda4819f289d5f9205afc" -string-length@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/string-length/-/string-length-1.0.1.tgz#56970fb1c38558e9e70b728bf3de269ac45adfac" - dependencies: - strip-ansi "^3.0.0" - -string-replace-webpack-plugin@0.0.3: - version "0.0.3" - resolved "https://registry.yarnpkg.com/string-replace-webpack-plugin/-/string-replace-webpack-plugin-0.0.3.tgz#82c67448cea95ec002a1bfcfd2fb0195cd12bd24" +string-replace-webpack-plugin@^0.1.3: + version "0.1.3" + resolved "https://registry.yarnpkg.com/string-replace-webpack-plugin/-/string-replace-webpack-plugin-0.1.3.tgz#73c657e759d66cfe80ae1e0cf091aa256d0e715c" dependencies: async "~0.2.10" + loader-utils "~0.2.3" + optionalDependencies: css-loader "^0.9.1" file-loader "^0.8.1" - loader-utils "~0.2.3" style-loader "^0.8.3" string-tools@^0.1.4: @@ -6767,7 +6851,7 @@ string-tools@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/string-tools/-/string-tools-1.0.0.tgz#c69a9d5788858997da66f1d923ba7113ea466b5a" -string-width@^1.0.1: +string-width@^1.0.1, string-width@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" dependencies: @@ -6775,23 +6859,22 @@ string-width@^1.0.1: is-fullwidth-code-point "^1.0.0" strip-ansi "^3.0.0" +string-width@^2.0.0, string-width@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.0.tgz#030664561fc146c9423ec7d978fe2457437fe6d0" + dependencies: + is-fullwidth-code-point "^2.0.0" + strip-ansi "^4.0.0" + string_decoder@^0.10.25, string_decoder@~0.10.x: version "0.10.31" resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94" -string_decoder@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.0.0.tgz#f06f41157b664d86069f84bdbdc9b0d8ab281667" +string_decoder@~1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.0.3.tgz#0fc67d7c141825de94282dd536bec6b9bce860ab" dependencies: - buffer-shims "~1.0.0" - -stringmap@~0.2.2: - version "0.2.2" - resolved "https://registry.yarnpkg.com/stringmap/-/stringmap-0.2.2.tgz#556c137b258f942b8776f5b2ef582aa069d7d1b1" - -stringset@~0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/stringset/-/stringset-0.2.1.tgz#ef259c4e349344377fcd1c913dd2e848c9c042b5" + safe-buffer "~5.1.0" stringstream@~0.0.4: version "0.0.5" @@ -6815,9 +6898,15 @@ strip-ansi@^3.0.0, strip-ansi@^3.0.1: dependencies: ansi-regex "^2.0.0" -strip-ansi@~0.1.0: - version "0.1.1" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-0.1.1.tgz#39e8a98d044d150660abe4a6808acf70bb7bc991" +strip-ansi@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f" + dependencies: + ansi-regex "^3.0.0" + +strip-bom-string@1.X: + version "1.0.0" + resolved "https://registry.yarnpkg.com/strip-bom-string/-/strip-bom-string-1.0.0.tgz#e5211e9224369fbb81d633a2f00044dc8cedad92" strip-bom@^1.0.0: version "1.0.0" @@ -6832,16 +6921,16 @@ strip-bom@^2.0.0: dependencies: is-utf8 "^0.2.0" +strip-bom@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" + strip-indent@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/strip-indent/-/strip-indent-1.0.1.tgz#0c7962a6adefa7bbd4ac366460a638552ae1a0a2" dependencies: get-stdin "^4.0.1" -strip-json-comments@1.0.x, strip-json-comments@~1.0.2: - version "1.0.4" - resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-1.0.4.tgz#1e15fbcac97d3ee99bf2d73b4c656b082bbafb91" - strip-json-comments@~2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" @@ -6852,10 +6941,6 @@ style-loader@^0.8.3: dependencies: loader-utils "^0.2.5" -supports-color@1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-1.2.0.tgz#ff1ed1e61169d06b3cf2d588e188b18d8847e17e" - supports-color@3.1.2: version "3.1.2" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-3.1.2.tgz#72a262894d9d408b956ca05ff37b2ed8a6e2a2d5" @@ -6874,12 +6959,18 @@ supports-color@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" -supports-color@^3.1.0: +supports-color@^3.1.0, supports-color@^3.1.2: version "3.2.3" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-3.2.3.tgz#65ac0504b3954171d8a64946b2ae3cbb8a5f54f6" dependencies: has-flag "^1.0.0" +supports-color@^4.0.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-4.2.0.tgz#ad986dc7eb2315d009b4d77c8169c2231a684037" + dependencies: + has-flag "^2.0.0" + table-layout@^0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/table-layout/-/table-layout-0.3.0.tgz#6ee20dc483db371b3e5c87f704ed2f7c799d2c9a" @@ -6891,6 +6982,17 @@ table-layout@^0.3.0: typical "^2.6.0" wordwrapjs "^2.0.0-0" +table@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/table/-/table-4.0.1.tgz#a8116c133fac2c61f4a420ab6cdf5c4d61f0e435" + dependencies: + ajv "^4.7.0" + ajv-keywords "^1.0.0" + chalk "^1.1.1" + lodash "^4.0.0" + slice-ansi "0.0.4" + string-width "^2.0.0" + taffydb@2.6.2: version "2.6.2" resolved "https://registry.yarnpkg.com/taffydb/-/taffydb-2.6.2.tgz#7cbcb64b5a141b6a2efc2c5d2c67b4e150b2a268" @@ -6899,6 +7001,10 @@ tapable@^0.1.8, tapable@~0.1.8: version "0.1.10" resolved "https://registry.yarnpkg.com/tapable/-/tapable-0.1.10.tgz#29c35707c2b70e50d07482b5d202e8ed446dafd4" +tapable@^0.2.5, tapable@~0.2.5: + version "0.2.6" + resolved "https://registry.yarnpkg.com/tapable/-/tapable-0.2.6.tgz#206be8e188860b514425375e6f1ae89bfb01fd8d" + tar-pack@^3.4.0: version "3.4.0" resolved "https://registry.yarnpkg.com/tar-pack/-/tar-pack-3.4.0.tgz#23be2d7f671a8339376cbdb0b8fe3fdebf317984" @@ -6912,6 +7018,15 @@ tar-pack@^3.4.0: tar "^2.2.1" uid-number "^0.0.6" +tar-stream@^1.5.0: + version "1.5.4" + resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-1.5.4.tgz#36549cf04ed1aee9b2a30c0143252238daf94016" + dependencies: + bl "^1.0.0" + end-of-stream "^1.0.0" + readable-stream "^2.0.0" + xtend "^4.0.0" + tar-stream@~1.1.0: version "1.1.5" resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-1.1.5.tgz#be9218c130c20029e107b0f967fb23de0579d13c" @@ -6933,12 +7048,14 @@ temp-path@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/temp-path/-/temp-path-1.0.0.tgz#24b1543973ab442896d9ad367dd9cbdbfafe918b" -temp@^0.8.3: - version "0.8.3" - resolved "https://registry.yarnpkg.com/temp/-/temp-0.8.3.tgz#e0c6bc4d26b903124410e4fed81103014dfc1f59" +ternary-stream@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/ternary-stream/-/ternary-stream-2.0.1.tgz#064e489b4b5bf60ba6a6b7bc7f2f5c274ecf8269" dependencies: - os-tmpdir "^1.0.0" - rimraf "~2.2.6" + duplexify "^3.5.0" + fork-stream "^0.0.4" + merge-stream "^1.0.0" + through2 "^2.0.1" test-value@^1.0.1, test-value@^1.1.0: version "1.1.0" @@ -6954,7 +7071,7 @@ test-value@^2.0.0, test-value@^2.1.0: array-back "^1.0.3" typical "^2.6.0" -text-table@^0.2.0: +text-table@~0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" @@ -6968,16 +7085,12 @@ then-fs@^2.0.0: dependencies: promise ">=3.2 <8" -throttleit@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/throttleit/-/throttleit-1.0.0.tgz#9e785836daf46743145a5984b6268d828528ac6c" - -"through2@>=0.6.1 <1.0.0-0", through2@^0.6.1, through2@^0.6.5, through2@~0.6.1: - version "0.6.5" - resolved "https://registry.yarnpkg.com/through2/-/through2-0.6.5.tgz#41ab9c67b29d57209071410e1d7a7a968cd3ad48" +through2@2.X, through2@^2.0.0, through2@^2.0.1, through2@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/through2/-/through2-2.0.3.tgz#0004569b37c7c74ba39c43f3ced78d1ad94140be" dependencies: - readable-stream ">=1.0.33-1 <1.1.0-0" - xtend ">=4.0.0 <4.1.0-0" + readable-stream "^2.1.5" + xtend "~4.0.1" through2@^0.4.2: version "0.4.2" @@ -6993,14 +7106,14 @@ through2@^0.5.0: readable-stream "~1.0.17" xtend "~3.0.0" -through2@^2.0.0, through2@^2.0.1: - version "2.0.3" - resolved "https://registry.yarnpkg.com/through2/-/through2-2.0.3.tgz#0004569b37c7c74ba39c43f3ced78d1ad94140be" +through2@^0.6.1, through2@^0.6.5: + version "0.6.5" + resolved "https://registry.yarnpkg.com/through2/-/through2-0.6.5.tgz#41ab9c67b29d57209071410e1d7a7a968cd3ad48" dependencies: - readable-stream "^2.1.5" - xtend "~4.0.1" + readable-stream ">=1.0.33-1 <1.1.0-0" + xtend ">=4.0.0 <4.1.0-0" -through@2, through@^2.3.4, through@^2.3.6, through@^2.3.8, through@~2.3, through@~2.3.1, through@~2.3.4, through@~2.3.8: +through@2, through@^2.3.6, through@^2.3.8, through@~2.3, through@~2.3.1, through@~2.3.4: version "2.3.8" resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" @@ -7015,8 +7128,8 @@ tildify@^1.0.0: os-homedir "^1.0.0" time-stamp@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/time-stamp/-/time-stamp-1.0.1.tgz#9f4bd23559c9365966f3302dbba2b07c6b99b151" + version "1.1.0" + resolved "https://registry.yarnpkg.com/time-stamp/-/time-stamp-1.1.0.tgz#764a5a11af50561921b133f3b44e618687e0f5c3" timers-browserify@^2.0.2: version "2.0.2" @@ -7024,6 +7137,13 @@ timers-browserify@^2.0.2: dependencies: setimmediate "^1.0.4" +timers-ext@0.1: + version "0.1.2" + resolved "https://registry.yarnpkg.com/timers-ext/-/timers-ext-0.1.2.tgz#61cc47a76c1abd3195f14527f978d58ae94c5204" + dependencies: + es5-ext "~0.10.14" + next-tick "1" + tiny-lr@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/tiny-lr/-/tiny-lr-0.2.1.tgz#b3fdba802e5d56a33c2f6f10794b32e477ac729d" @@ -7035,7 +7155,7 @@ tiny-lr@^0.2.1: parseurl "~1.3.0" qs "~5.1.0" -tmp@0.0.x: +tmp@0.0.31, tmp@0.0.x, tmp@^0.0.31: version "0.0.31" resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.31.tgz#8f38ab9438e17315e5dbd8b3657e8bfb277ae4a7" dependencies: @@ -7049,21 +7169,9 @@ to-arraybuffer@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz#7d229b1fcc637e466ca081180836a7aabff83f43" -to-double-quotes@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/to-double-quotes/-/to-double-quotes-2.0.0.tgz#aaf231d6fa948949f819301bbab4484d8588e4a7" - -to-fast-properties@^1.0.0, to-fast-properties@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-1.0.2.tgz#f3f5c0c3ba7299a7ef99427e44633257ade43320" - -to-iso-string@0.0.2: - version "0.0.2" - resolved "https://registry.yarnpkg.com/to-iso-string/-/to-iso-string-0.0.2.tgz#4dc19e664dfccbe25bd8db508b00c6da158255d1" - -to-single-quotes@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/to-single-quotes/-/to-single-quotes-2.0.1.tgz#7cc29151f0f5f2c41946f119f5932fe554170125" +to-fast-properties@^1.0.1: + version "1.0.3" + resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-1.0.3.tgz#b83571fa4d8c25b82e231b06e3a3055de4ca1a47" tough-cookie@>=0.12.0, tough-cookie@~2.3.0: version "2.3.2" @@ -7071,10 +7179,6 @@ tough-cookie@>=0.12.0, tough-cookie@~2.3.0: dependencies: punycode "^1.4.1" -tough-cookie@~2.2.0: - version "2.2.2" - resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.2.2.tgz#c83a1830f4e5ef0b93ef2a3488e724f8de016ac7" - "traverse@>=0.3.0 <0.4": version "0.3.9" resolved "https://registry.yarnpkg.com/traverse/-/traverse-0.3.9.tgz#717b8f220cc0bb7b44e40514c22b2e8bbc70d8b9" @@ -7083,17 +7187,13 @@ trim-newlines@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/trim-newlines/-/trim-newlines-1.0.0.tgz#5887966bb582a4503a41eb524f7d35011815a613" -trim-right@^1.0.0, trim-right@^1.0.1: +trim-right@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/trim-right/-/trim-right-1.0.1.tgz#cb2e1203067e0c8de1f614094b9fe45704ea6003" -try-resolve@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/try-resolve/-/try-resolve-1.0.1.tgz#cfde6fabd72d63e5797cfaab873abbe8e700e912" - -tryor@~0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/tryor/-/tryor-0.1.2.tgz#8145e4ca7caff40acde3ccf946e8b8bb75b4172b" +tryit@^1.0.1: + version "1.0.3" + resolved "https://registry.yarnpkg.com/tryit/-/tryit-1.0.3.tgz#393be730a9446fd1ead6da59a014308f36c289cb" tsscmp@1.0.5: version "1.0.5" @@ -7117,7 +7217,7 @@ tweetnacl@^0.14.3, tweetnacl@~0.14.0: version "0.14.5" resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" -type-check@~0.3.1: +type-check@~0.3.2: version "0.3.2" resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72" dependencies: @@ -7131,39 +7231,37 @@ type-detect@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-1.0.0.tgz#762217cc06db258ec48908a1298e8b95121e8ea2" -type-is@~1.6.10, type-is@~1.6.14, type-is@~1.6.6: +type-is@~1.6.10, type-is@~1.6.15, type-is@~1.6.6: version "1.6.15" resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.15.tgz#cab10fb4909e441c82842eafe1ad646c81804410" dependencies: media-typer "0.3.0" mime-types "~2.1.15" -typedarray@^0.0.6, typedarray@~0.0.5: +typedarray@^0.0.6: version "0.0.6" resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" -typical@^2.1, typical@^2.2, typical@^2.3.0, typical@^2.4.2, typical@^2.5.0, typical@^2.6.0: - version "2.6.0" - resolved "https://registry.yarnpkg.com/typical/-/typical-2.6.0.tgz#89d51554ab139848a65bcc2c8772f8fb450c40ed" - -uglify-js@2.4.6: - version "2.4.6" - resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-2.4.6.tgz#31766a4d822babf5f32c14096251ed9259298ad3" - dependencies: - async "~0.2.6" - optimist "~0.3.5" - source-map "~0.1.7" - uglify-to-browserify "~1.0.0" +typical@^2.1, typical@^2.2, typical@^2.3.0, typical@^2.4.2, typical@^2.5.0, typical@^2.6.0, typical@^2.6.1: + version "2.6.1" + resolved "https://registry.yarnpkg.com/typical/-/typical-2.6.1.tgz#5c080e5d661cbbe38259d2e70a3c7253e873881d" -uglify-js@^2.6, uglify-js@^2.8.10: - version "2.8.21" - resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-2.8.21.tgz#1733f669ae6f82fc90c7b25ec0f5c783ee375314" +uglify-js@^2.6, uglify-js@^2.8.10, uglify-js@^2.8.29: + version "2.8.29" + resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-2.8.29.tgz#29c5733148057bb4e1f75df35b7a9cb72e6a59dd" dependencies: source-map "~0.5.1" yargs "~3.10.0" optionalDependencies: uglify-to-browserify "~1.0.0" +uglify-js@^3.0.5: + version "3.0.24" + resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.0.24.tgz#ee93400ad9857fb7a1671778db83f6a23f033121" + dependencies: + commander "~2.9.0" + source-map "~0.5.1" + uglify-js@~2.3: version "2.3.6" resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-2.3.6.tgz#fa0984770b428b7a9b2a8058f46355d14fef211a" @@ -7185,6 +7283,14 @@ uglify-to-browserify@~1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz#6e0924d6bda6b5afe349e39a6d632850a0f882b7" +uglifyjs-webpack-plugin@^0.4.6: + version "0.4.6" + resolved "https://registry.yarnpkg.com/uglifyjs-webpack-plugin/-/uglifyjs-webpack-plugin-0.4.6.tgz#b951f4abb6bd617e66f63eb891498e391763e309" + dependencies: + source-map "^0.5.6" + uglify-js "^2.8.29" + webpack-sources "^1.0.1" + uid-number@^0.0.6: version "0.0.6" resolved "https://registry.yarnpkg.com/uid-number/-/uid-number-0.0.6.tgz#0ea10e8035e8eb5b8e4449f06da1c730663baa81" @@ -7215,9 +7321,12 @@ underscore-contrib@~0.3.0: dependencies: underscore "1.6.0" -underscore.string@~3.0.3: - version "3.0.3" - resolved "https://registry.yarnpkg.com/underscore.string/-/underscore.string-3.0.3.tgz#4617b8c1a250cf6e5064fbbb363d0fa96cf14552" +underscore.string@3.3.4: + version "3.3.4" + resolved "https://registry.yarnpkg.com/underscore.string/-/underscore.string-3.3.4.tgz#2c2a3f9f83e64762fdc45e6ceac65142864213db" + dependencies: + sprintf-js "^1.0.3" + util-deprecate "^1.0.2" underscore@1.6.0, underscore@~1.6.0: version "1.6.0" @@ -7251,10 +7360,10 @@ urix@^0.1.0, urix@~0.1.0: resolved "https://registry.yarnpkg.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72" url-parse@^1.0.5: - version "1.1.8" - resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.1.8.tgz#7a65b3a8d57a1e86af6b4e2276e34774167c0156" + version "1.1.9" + resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.1.9.tgz#c67f1d775d51f0a18911dd7b3ffad27bb9e5bd19" dependencies: - querystringify "0.0.x" + querystringify "~1.0.0" requires-port "1.0.x" url@^0.11.0: @@ -7272,31 +7381,31 @@ url@~0.10.3: querystring "0.2.0" usage-stats@^0.8.2: - version "0.8.2" - resolved "https://registry.yarnpkg.com/usage-stats/-/usage-stats-0.8.2.tgz#d7be5203682e267f7696b354356c8c376aa12542" + version "0.8.6" + resolved "https://registry.yarnpkg.com/usage-stats/-/usage-stats-0.8.6.tgz#ec92559f648845c2021cbf5b4adea17af7513830" dependencies: - array-back "^1.0.3" + array-back "^1.0.4" cli-commands "0.1.0" core-js "^2.4.1" feature-detect-es6 "^1.3.1" - home-path "^1.0.3" - mkdirp "^0.5.1" - req-then "^0.5.1" - typical "^2.6.0" - uuid "^3.0.0" + home-path "^1.0.5" + mkdirp2 "^1.0.3" + req-then "0.5.1" + typical "^2.6.1" + uuid "^3.0.1" user-home@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/user-home/-/user-home-1.1.1.tgz#2b5be23a32b63a7c9deb8d0f28d485724a3df190" -useragent@^2.1.6: - version "2.1.13" - resolved "https://registry.yarnpkg.com/useragent/-/useragent-2.1.13.tgz#bba43e8aa24d5ceb83c2937473e102e21df74c10" +useragent@^2.1.12: + version "2.2.1" + resolved "https://registry.yarnpkg.com/useragent/-/useragent-2.2.1.tgz#cf593ef4f2d175875e8bb658ea92e18a4fd06d8e" dependencies: lru-cache "2.2.x" tmp "0.0.x" -util-deprecate@~1.0.1: +util-deprecate@^1.0.2, util-deprecate@~1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" @@ -7306,32 +7415,17 @@ util@0.10.3, "util@>=0.10.3 <1", util@^0.10.3: dependencies: inherits "2.0.1" -utile@0.2.x: - version "0.2.1" - resolved "https://registry.yarnpkg.com/utile/-/utile-0.2.1.tgz#930c88e99098d6220834c356cbd9a770522d90d7" - dependencies: - async "~0.2.9" - deep-equal "*" - i "0.3.x" - mkdirp "0.x.x" - ncp "0.4.x" - rimraf "2.x.x" - utils-merge@1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.0.tgz#0294fb922bb9375153541c4f7096231f287c8af8" -uuid@^2.0.2: - version "2.0.3" - resolved "https://registry.yarnpkg.com/uuid/-/uuid-2.0.3.tgz#67e2e863797215530dff318e5bf9dcebfd47b21a" - -uuid@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.0.1.tgz#6544bba2dfda8c1cf17e629a3a305e2bb1fee6c1" +uuid@^3.0.0, uuid@^3.0.1: + version "3.1.0" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.1.0.tgz#3dd3d3e790abc24d7b0d3a034ffababe28ebbc04" v8flags@^2.0.2: - version "2.0.12" - resolved "https://registry.yarnpkg.com/v8flags/-/v8flags-2.0.12.tgz#73235d9f7176f8e8833fb286795445f7938d84e5" + version "2.1.1" + resolved "https://registry.yarnpkg.com/v8flags/-/v8flags-2.1.1.tgz#aab1a1fa30d45f88dd321148875ac02c0b55e5b4" dependencies: user-home "^1.1.1" @@ -7342,7 +7436,7 @@ validate-npm-package-license@^3.0.1: spdx-correct "~1.0.0" spdx-expression-parse "~1.0.0" -vargs@~0.1.0: +vargs@0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/vargs/-/vargs-0.1.0.tgz#6b6184da6520cc3204ce1b407cac26d92609ebff" @@ -7350,7 +7444,7 @@ vary@~1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/vary/-/vary-1.0.1.tgz#99e4981566a286118dfb2b817357df7993376d10" -vary@~1.1.0: +vary@~1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.1.tgz#67535ebb694c1d52257457984665323f587e8d37" @@ -7383,6 +7477,14 @@ vinyl-sourcemaps-apply@^0.2.0: dependencies: source-map "^0.5.1" +vinyl@1.X, vinyl@^1.1.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/vinyl/-/vinyl-1.2.0.tgz#5c88036cf565e5df05558bfc911f8656df218884" + dependencies: + clone "^1.0.0" + clone-stats "^0.0.1" + replace-ext "0.0.1" + vinyl@^0.2.1: version "0.2.3" resolved "https://registry.yarnpkg.com/vinyl/-/vinyl-0.2.3.tgz#bca938209582ec5a49ad538a00fa1f125e513252" @@ -7404,29 +7506,20 @@ vinyl@^0.5.0: clone-stats "^0.0.1" replace-ext "0.0.1" -vinyl@^1.1.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/vinyl/-/vinyl-1.2.0.tgz#5c88036cf565e5df05558bfc911f8656df218884" - dependencies: - clone "^1.0.0" - clone-stats "^0.0.1" - replace-ext "0.0.1" - vinyl@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/vinyl/-/vinyl-2.0.1.tgz#1c3b4931e7ac4c1efee743f3b91a74c094407bb6" + version "2.1.0" + resolved "https://registry.yarnpkg.com/vinyl/-/vinyl-2.1.0.tgz#021f9c2cf951d6b939943c89eb5ee5add4fd924c" dependencies: - clone "^1.0.0" + clone "^2.1.1" clone-buffer "^1.0.0" clone-stats "^1.0.0" cloneable-readable "^1.0.0" - is-stream "^1.1.0" remove-trailing-separator "^1.0.1" replace-ext "^1.0.0" vlq@^0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/vlq/-/vlq-0.2.1.tgz#14439d711891e682535467f8587c5630e4222a6c" + version "0.2.2" + resolved "https://registry.yarnpkg.com/vlq/-/vlq-0.2.2.tgz#e316d5257b40b86bb43cb8d5fea5d7f54d6b0ca1" vm-browserify@0.0.4: version "0.0.4" @@ -7438,25 +7531,6 @@ void-elements@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/void-elements/-/void-elements-2.0.1.tgz#c066afb582bb1cb4128d60ea92392e94d5e9dbec" -vow-fs@~0.3.4: - version "0.3.6" - resolved "https://registry.yarnpkg.com/vow-fs/-/vow-fs-0.3.6.tgz#2d4c59be22e2bf2618ddf597ab4baa923be7200d" - dependencies: - glob "^7.0.5" - uuid "^2.0.2" - vow "^0.4.7" - vow-queue "^0.4.1" - -vow-queue@^0.4.1: - version "0.4.2" - resolved "https://registry.yarnpkg.com/vow-queue/-/vow-queue-0.4.2.tgz#e7fe17160e15c7c4184d1b666a9bc64e18e30184" - dependencies: - vow "~0.4.0" - -vow@^0.4.7, vow@~0.4.0, vow@~0.4.8: - version "0.4.15" - resolved "https://registry.yarnpkg.com/vow/-/vow-0.4.15.tgz#0579163aff6ba0ae05c456b2c0e4ca6373f111b3" - walk-back@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/walk-back/-/walk-back-2.0.1.tgz#554e2a9d874fac47a8cb006bf44c2f0c4998a0a4" @@ -7467,6 +7541,10 @@ walk@^2.3.9: dependencies: foreachasync "^3.0.0" +walkdir@^0.0.11: + version "0.0.11" + resolved "https://registry.yarnpkg.com/walkdir/-/walkdir-0.0.11.tgz#a16d025eb931bd03b52f308caed0f40fcebe9532" + watchpack@^0.2.1: version "0.2.9" resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-0.2.9.tgz#62eaa4ab5e5ba35fdfc018275626e3c0f5e3fb0b" @@ -7475,17 +7553,26 @@ watchpack@^0.2.1: chokidar "^1.0.0" graceful-fs "^4.1.2" -wd@~0.3.4: - version "0.3.12" - resolved "https://registry.yarnpkg.com/wd/-/wd-0.3.12.tgz#3fb4f1d759f8c85dde5393d17334ffe03e9bb329" +watchpack@^1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-1.3.1.tgz#7d8693907b28ce6013e7f3610aa2a1acf07dad87" + dependencies: + async "^2.1.2" + chokidar "^1.4.3" + graceful-fs "^4.1.2" + +wd@^1.0.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/wd/-/wd-1.3.0.tgz#fdbdfbe192805b1cbd7943375642f06d990bccef" dependencies: - archiver "~0.14.0" - async "~1.0.0" - lodash "~3.9.3" - q "~1.4.1" - request "~2.55.0" - underscore.string "~3.0.3" - vargs "~0.1.0" + archiver "1.3.0" + async "2.0.1" + lodash "4.16.2" + mkdirp "^0.5.1" + q "1.4.1" + request "2.79.0" + underscore.string "3.3.4" + vargs "0.1.0" webdriverio@^3.4.0: version "3.4.0" @@ -7517,15 +7604,22 @@ webpack-core@~0.6.9: source-map "~0.4.1" webpack-dev-middleware@^1.0.11: - version "1.10.1" - resolved "https://registry.yarnpkg.com/webpack-dev-middleware/-/webpack-dev-middleware-1.10.1.tgz#c6b4cf428139cf1aefbe06a0c00fdb4f8da2f893" + version "1.11.0" + resolved "https://registry.yarnpkg.com/webpack-dev-middleware/-/webpack-dev-middleware-1.11.0.tgz#09691d0973a30ad1f82ac73a12e2087f0a4754f9" dependencies: memory-fs "~0.4.1" mime "^1.3.4" path-is-absolute "^1.0.0" range-parser "^1.0.3" -webpack-stream@^3.1.0: +webpack-sources@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-1.0.1.tgz#c7356436a4d13123be2e2426a05d1dad9cbe65cf" + dependencies: + source-list-map "^2.0.0" + source-map "~0.5.3" + +webpack-stream@^3.2.0: version "3.2.0" resolved "https://registry.yarnpkg.com/webpack-stream/-/webpack-stream-3.2.0.tgz#3a1d160fb11d41727b7ce6f32f722464f98b2186" dependencies: @@ -7537,9 +7631,9 @@ webpack-stream@^3.1.0: vinyl "^1.1.0" webpack "^1.12.9" -webpack@^1.12.3, webpack@^1.12.9: - version "1.14.0" - resolved "https://registry.yarnpkg.com/webpack/-/webpack-1.14.0.tgz#54f1ffb92051a328a5b2057d6ae33c289462c823" +webpack@^1.12.9: + version "1.15.0" + resolved "https://registry.yarnpkg.com/webpack/-/webpack-1.15.0.tgz#4ff31f53db03339e55164a9d468ee0324968fe98" dependencies: acorn "^3.0.0" async "^1.3.0" @@ -7557,6 +7651,33 @@ webpack@^1.12.3, webpack@^1.12.9: watchpack "^0.2.1" webpack-core "~0.6.9" +webpack@^3.0.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/webpack/-/webpack-3.2.0.tgz#8b0cae0e1a9fd76bfbf0eab61a8c2ada848c312f" + dependencies: + acorn "^5.0.0" + acorn-dynamic-import "^2.0.0" + ajv "^5.1.5" + ajv-keywords "^2.0.0" + async "^2.1.2" + enhanced-resolve "^3.3.0" + escope "^3.6.0" + interpret "^1.0.0" + json-loader "^0.5.4" + json5 "^0.5.1" + loader-runner "^2.3.0" + loader-utils "^1.1.0" + memory-fs "~0.4.1" + mkdirp "~0.5.0" + node-libs-browser "^2.0.0" + source-map "^0.5.3" + supports-color "^3.1.0" + tapable "~0.2.5" + uglifyjs-webpack-plugin "^0.4.6" + watchpack "^1.3.1" + webpack-sources "^1.0.1" + yargs "^6.0.0" + websocket-driver@>=0.5.1: version "0.6.5" resolved "https://registry.yarnpkg.com/websocket-driver/-/websocket-driver-0.6.5.tgz#5cb2556ceb85f4373c6d8238aa691c8454e13a36" @@ -7575,21 +7696,17 @@ which-module@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/which-module/-/which-module-1.0.0.tgz#bba63ca861948994ff307736089e3b96026c2a4f" -which@^1.1.1, which@^1.2.1, which@^1.2.12, which@~1.2.2: +which@^1.1.1, which@^1.2.1, which@^1.2.12: version "1.2.14" resolved "https://registry.yarnpkg.com/which/-/which-1.2.14.tgz#9a87c4378f03e827cecaf1acdf56c736c01c14e5" dependencies: isexe "^2.0.0" -which@~1.0.5: - version "1.0.9" - resolved "https://registry.yarnpkg.com/which/-/which-1.0.9.tgz#460c1da0f810103d0321a9b633af9e575e64486f" - wide-align@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.0.tgz#40edde802a71fea1f070da3e62dcda2e7add96ad" + version "1.1.2" + resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.2.tgz#571e0f1b0604636ebc0dfc21b0339bbe31341710" dependencies: - string-width "^1.0.1" + string-width "^1.0.2" window-size@0.1.0: version "0.1.0" @@ -7603,23 +7720,11 @@ window-size@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/window-size/-/window-size-0.2.0.tgz#b4315bb4214a3d7058ebeee892e13fa24d98b075" -winston@0.8.x: - version "0.8.3" - resolved "https://registry.yarnpkg.com/winston/-/winston-0.8.3.tgz#64b6abf4cd01adcaefd5009393b1d8e8bec19db0" - dependencies: - async "0.2.x" - colors "0.6.x" - cycle "1.0.x" - eyes "0.1.x" - isstream "0.1.x" - pkginfo "0.3.x" - stack-trace "0.0.x" - wordwrap@0.0.2: version "0.0.2" resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.2.tgz#b79669bb42ecb409f83d583cad52ca17eaa1643f" -wordwrap@^1.0.0: +wordwrap@^1.0.0, wordwrap@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" @@ -7654,6 +7759,12 @@ wrappy@1: version "1.0.2" resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" +write@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/write/-/write-0.2.1.tgz#5fc03828e264cea3fe91455476f7a3c566cb0757" + dependencies: + mkdirp "^0.5.1" + ws@1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/ws/-/ws-1.1.2.tgz#8a244fa052401e08c9886cf44a85189e1fd4067f" @@ -7665,12 +7776,6 @@ wtf-8@1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/wtf-8/-/wtf-8-1.0.0.tgz#392d8ba2d0f1c34d1ee2d630f15d0efb68e1048a" -xmlbuilder@3.1.0, xmlbuilder@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-3.1.0.tgz#2c86888f2d4eade850fa38ca7f7223f7209516e1" - dependencies: - lodash "^3.5.0" - xmlhttprequest-ssl@1.5.3: version "1.5.3" resolved "https://registry.yarnpkg.com/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.3.tgz#185a888c04eca46c3e4070d99f7b49de3528992d" @@ -7704,6 +7809,12 @@ yargs-parser@^2.4.1: camelcase "^3.0.0" lodash.assign "^4.0.6" +yargs-parser@^4.2.0: + version "4.2.1" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-4.2.1.tgz#29cceac0dc4f03c6c87b4a9f217dd18c9f74871c" + dependencies: + camelcase "^3.0.0" + yargs@3.29.0: version "3.29.0" resolved "https://registry.yarnpkg.com/yargs/-/yargs-3.29.0.tgz#1aab9660eae79d8b8f675bcaeeab6ee34c2cf69c" @@ -7738,6 +7849,24 @@ yargs@^4.8.1: y18n "^3.2.1" yargs-parser "^2.4.1" +yargs@^6.0.0: + version "6.6.0" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-6.6.0.tgz#782ec21ef403345f830a808ca3d513af56065208" + dependencies: + camelcase "^3.0.0" + cliui "^3.2.0" + decamelize "^1.1.1" + get-caller-file "^1.0.1" + os-locale "^1.4.0" + read-pkg-up "^1.0.1" + require-directory "^2.1.1" + require-main-filename "^1.0.1" + set-blocking "^2.0.0" + string-width "^1.0.2" + which-module "^1.0.0" + y18n "^3.2.1" + yargs-parser "^4.2.0" + yargs@~3.10.0: version "3.10.0" resolved "https://registry.yarnpkg.com/yargs/-/yargs-3.10.0.tgz#f7ee7bd857dd7c1d2d38c0e74efbd681d1431fd1" @@ -7747,33 +7876,19 @@ yargs@~3.10.0: decamelize "^1.0.0" window-size "0.1.0" -yargs@~3.27.0: - version "3.27.0" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-3.27.0.tgz#21205469316e939131d59f2da0c6d7f98221ea40" - dependencies: - camelcase "^1.2.1" - cliui "^2.1.0" - decamelize "^1.0.0" - os-locale "^1.4.0" - window-size "^0.1.2" - y18n "^3.2.0" - -yauzl@2.4.1: - version "2.4.1" - resolved "https://registry.yarnpkg.com/yauzl/-/yauzl-2.4.1.tgz#9528f442dab1b2284e58b4379bb194e22e0c4005" - dependencies: - fd-slicer "~1.0.1" - -yazl@^2.1.0: - version "2.4.2" - resolved "https://registry.yarnpkg.com/yazl/-/yazl-2.4.2.tgz#14cb19083e1e25a70092c1588aabe0f4e4dd4d88" - dependencies: - buffer-crc32 "~0.2.3" - yeast@0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/yeast/-/yeast-0.1.2.tgz#008e06d8094320c372dbc2f8ed76a0ca6c8ac419" +zip-stream@^1.1.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/zip-stream/-/zip-stream-1.2.0.tgz#a8bc45f4c1b49699c6b90198baacaacdbcd4ba04" + dependencies: + archiver-utils "^1.3.0" + compress-commons "^1.2.0" + lodash "^4.8.0" + readable-stream "^2.0.0" + zip-stream@~0.5.0: version "0.5.2" resolved "https://registry.yarnpkg.com/zip-stream/-/zip-stream-0.5.2.tgz#32dcbc506d0dab4d21372625bd7ebaac3c2fff56"