diff --git a/.circleci/config.yaml b/.circleci/config.yaml new file mode 100644 index 0000000..ae781c1 --- /dev/null +++ b/.circleci/config.yaml @@ -0,0 +1,37 @@ +# Javascript Node CircleCI 2.0 configuration file +# +# Check https://circleci.com/docs/2.0/language-javascript/ for more details +# +version: 2 +jobs: + build: + docker: + # specify the version you desire here + - image: circleci/node:7.10 + + # Specify service dependencies here if necessary + # CircleCI maintains a library of pre-built images + # documented at https://circleci.com/docs/2.0/circleci-images/ + # - image: circleci/mongo:3.4.4 + + working_directory: ~/repo + + steps: + - checkout + + # Download and cache dependencies + - restore_cache: + keys: + - v1-dependencies-{{ checksum "package.json" }} + # fallback to using the latest cache if no exact match is found + - v1-dependencies- + + - run: yarn install + + - save_cache: + paths: + - node_modules + key: v1-dependencies-{{ checksum "package.json" }} + + # run tests! + - run: yarn test diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c2658d7 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +node_modules/ diff --git a/Gruntfile.js b/Gruntfile.js new file mode 100644 index 0000000..9c8cbfe --- /dev/null +++ b/Gruntfile.js @@ -0,0 +1,47 @@ +'use strict'; + +var path = require('path'); + +module.exports = function(grunt) { + + grunt.initConfig({ + + env: { + chrome: { + PLATFORM: 'CHROME' + }, + firefox: { + PLATFORM: 'FIREFOX' + }, + android: { + PLATFORM: 'ANDROID' + } + }, + + jshint: { + all: ['Gruntfile.js', 'features/step_definitions/*.js', 'features/support/*.js'], + options: { + node: true, + strict: true, + globalstrict: true, + 'esversion':6 + } + }, + + exec: { + run_cucumber_tests: { + command: 'node ' + path.join('node_modules', 'cucumber', 'bin', 'cucumber.js -f pretty -t @for_testing') + } + } + + }); + + grunt.loadNpmTasks('grunt-contrib-jshint'); + grunt.loadNpmTasks('grunt-exec'); + grunt.loadNpmTasks('grunt-env'); + + grunt.registerTask('default', ['jshint', 'exec']); + grunt.registerTask('chrome', ['env:chrome', 'jshint', 'exec']); + grunt.registerTask('firefox', ['env:firefox', 'jshint', 'exec']); + +}; diff --git a/README.md b/README.md index 18486b0..14e2fd5 100644 --- a/README.md +++ b/README.md @@ -8,4 +8,5 @@ * https://www.slideshare.net/qaoth/the-art-of-gherkin-scripting-matt-eakin * https://github.com/wakaleo/movie-service/blob/master/src/test/resources/features/search/searching_for_movies.feature - +JSON Viewer +http://jsonviewer.stack.hu/ diff --git a/configuration.js b/configuration.js new file mode 100644 index 0000000..cf78e1d --- /dev/null +++ b/configuration.js @@ -0,0 +1,2 @@ +exports.BASE_URL="https://api.utu.ai/v1/"; +exports.TEST_TYPE="REST"; diff --git a/dialog/post_message.feature b/dialog/post_message.feature deleted file mode 100644 index 021e166..0000000 --- a/dialog/post_message.feature +++ /dev/null @@ -1,49 +0,0 @@ -@dialog @receive_message -Feature: new message - All valid messages - should be captured in their raw form - persisted - and then denorm'd to all related services - - Why: - - we can run sentiment models on user's text to evaluate their state of mind - - in the future, we will likely get in the intent business ourselves. having the raw data will be useful. - - in any consumer analytics environment, hold on to ALL the data you can, for as LONG as you can. - - Rules: - - the inbound message must containt a bot key (which kong decodes to org and botId) as well as p/pId - - Background: - Given there are Identity records as follows: - | identityKey | - | TIN_RECORD | - | BRONZE_RECORD | - | GOLD_RECORD | - And Dialog records as follows: - | dialogKey | - | DIALOG_RECORD | - - @acceptance @valid_message_received - Scenario: Received valid message from existing user for active dialog - When a valid new message is received for an existing user who is actively dialoging - Then save the message - And update dialog - And update identity - And create a summarized event - - @acceptance @valid_message_received - Scenario: Received valid message from existing user for new dialog - When a valid new message is received for an existing user starting a new dialog - Then save the message - And update dialog - And update identity - And create a summarized event - - @acceptance @valid_message_received - Scenario: Received valid message from new user - When a valid new message is received from a new user - Then save the message - And update dialog - And update identity - And create a summarized event - diff --git a/features/dialog/dialog.log b/features/dialog/dialog.log new file mode 100644 index 0000000..9a17c1b --- /dev/null +++ b/features/dialog/dialog.log @@ -0,0 +1,216 @@ +Running "jshint:all" (jshint) task +>> 1 file lint free. + +Running "exec:run_cucumber_tests" (exec) task +@dialog @receive_message +Feature: new message + + All valid messages + should be captured in their raw form + persisted + and then denorm'd to all related services + + Why: + - we can run sentiment models on user's text to evaluate their state of mind + - in the future, we will likely get in the intent business ourselves. having the raw data will be useful. + - in any consumer analytics environment, hold on to ALL the data you can, for as LONG as you can. + + Rules: + - the inbound message must containt a bot key (which kong decodes to org and botId) as well as p/pId + + @for_testing @acceptance @valid_message_received @for_testing + Scenario: Received valid message from existing user for active dialog + Given there are Identity records as follows: + | identityKey  | + | TIN_RECORD  | + | BRONZE_RECORD | + | GOLD_RECORD  | + When a valid new message is received for an existing user who is actively dialoging + Then save the Message + And update Dialog with Message + And update Identity with Message + And create a summarized Event for Message + + @acceptance @valid_message_received @for_testing + Scenario: Received valid message from existing user for new dialog + Given there are Identity records as follows: + | identityKey  | + | TIN_RECORD  | + | BRONZE_RECORD | + | GOLD_RECORD  | + When a valid new message is received for an existing user starting a new dialog + Then save the Message + And update Dialog with Message + And update Identity with Message + And create a summarized Event for Message + + @acceptance @valid_message_received @for_testing + Scenario: Received valid message from new user + Given there are Identity records as follows: + | identityKey  | + | TIN_RECORD  | + | BRONZE_RECORD | + | GOLD_RECORD  | + When a valid new message is received from a new user + Then save the Message + And update Dialog with Message + And update Identity with Message + And create a summarized Event for Message + +Warnings: + +1) Scenario: Received valid message from existing user for active dialog - features/dialog/post_message.feature:28 + Step: When a valid new message is received for an existing user who is actively dialoging - features/dialog/post_message.feature:29 + Message: + Undefined. Implement with the following snippet: + + this.When(/^a valid new message is received for an existing user who is actively dialoging$/, function (callback) { + // Write code here that turns the phrase above into concrete actions + callback(null, 'pending'); + }); + +2) Scenario: Received valid message from existing user for active dialog - features/dialog/post_message.feature:28 + Step: Then save the Message - features/dialog/post_message.feature:30 + Message: + Undefined. Implement with the following snippet: + + this.Then(/^save the Message$/, function (callback) { + // Write code here that turns the phrase above into concrete actions + callback(null, 'pending'); + }); + +3) Scenario: Received valid message from existing user for active dialog - features/dialog/post_message.feature:28 + Step: And update Dialog with Message - features/dialog/post_message.feature:31 + Message: + Undefined. Implement with the following snippet: + + this.Then(/^update Dialog with Message$/, function (callback) { + // Write code here that turns the phrase above into concrete actions + callback(null, 'pending'); + }); + +4) Scenario: Received valid message from existing user for active dialog - features/dialog/post_message.feature:28 + Step: And update Identity with Message - features/dialog/post_message.feature:32 + Message: + Undefined. Implement with the following snippet: + + this.Then(/^update Identity with Message$/, function (callback) { + // Write code here that turns the phrase above into concrete actions + callback(null, 'pending'); + }); + +5) Scenario: Received valid message from existing user for active dialog - features/dialog/post_message.feature:28 + Step: And create a summarized Event for Message - features/dialog/post_message.feature:33 + Message: + Undefined. Implement with the following snippet: + + this.Then(/^create a summarized Event for Message$/, function (callback) { + // Write code here that turns the phrase above into concrete actions + callback(null, 'pending'); + }); + +6) Scenario: Received valid message from existing user for new dialog - features/dialog/post_message.feature:36 + Step: When a valid new message is received for an existing user starting a new dialog - features/dialog/post_message.feature:37 + Message: + Undefined. Implement with the following snippet: + + this.When(/^a valid new message is received for an existing user starting a new dialog$/, function (callback) { + // Write code here that turns the phrase above into concrete actions + callback(null, 'pending'); + }); + +7) Scenario: Received valid message from existing user for new dialog - features/dialog/post_message.feature:36 + Step: Then save the Message - features/dialog/post_message.feature:38 + Message: + Undefined. Implement with the following snippet: + + this.Then(/^save the Message$/, function (callback) { + // Write code here that turns the phrase above into concrete actions + callback(null, 'pending'); + }); + +8) Scenario: Received valid message from existing user for new dialog - features/dialog/post_message.feature:36 + Step: And update Dialog with Message - features/dialog/post_message.feature:39 + Message: + Undefined. Implement with the following snippet: + + this.Then(/^update Dialog with Message$/, function (callback) { + // Write code here that turns the phrase above into concrete actions + callback(null, 'pending'); + }); + +9) Scenario: Received valid message from existing user for new dialog - features/dialog/post_message.feature:36 + Step: And update Identity with Message - features/dialog/post_message.feature:40 + Message: + Undefined. Implement with the following snippet: + + this.Then(/^update Identity with Message$/, function (callback) { + // Write code here that turns the phrase above into concrete actions + callback(null, 'pending'); + }); + +10) Scenario: Received valid message from existing user for new dialog - features/dialog/post_message.feature:36 + Step: And create a summarized Event for Message - features/dialog/post_message.feature:41 + Message: + Undefined. Implement with the following snippet: + + this.Then(/^create a summarized Event for Message$/, function (callback) { + // Write code here that turns the phrase above into concrete actions + callback(null, 'pending'); + }); + +11) Scenario: Received valid message from new user - features/dialog/post_message.feature:44 + Step: When a valid new message is received from a new user - features/dialog/post_message.feature:45 + Message: + Undefined. Implement with the following snippet: + + this.When(/^a valid new message is received from a new user$/, function (callback) { + // Write code here that turns the phrase above into concrete actions + callback(null, 'pending'); + }); + +12) Scenario: Received valid message from new user - features/dialog/post_message.feature:44 + Step: Then save the Message - features/dialog/post_message.feature:46 + Message: + Undefined. Implement with the following snippet: + + this.Then(/^save the Message$/, function (callback) { + // Write code here that turns the phrase above into concrete actions + callback(null, 'pending'); + }); + +13) Scenario: Received valid message from new user - features/dialog/post_message.feature:44 + Step: And update Dialog with Message - features/dialog/post_message.feature:47 + Message: + Undefined. Implement with the following snippet: + + this.Then(/^update Dialog with Message$/, function (callback) { + // Write code here that turns the phrase above into concrete actions + callback(null, 'pending'); + }); + +14) Scenario: Received valid message from new user - features/dialog/post_message.feature:44 + Step: And update Identity with Message - features/dialog/post_message.feature:48 + Message: + Undefined. Implement with the following snippet: + + this.Then(/^update Identity with Message$/, function (callback) { + // Write code here that turns the phrase above into concrete actions + callback(null, 'pending'); + }); + +15) Scenario: Received valid message from new user - features/dialog/post_message.feature:44 + Step: And create a summarized Event for Message - features/dialog/post_message.feature:49 + Message: + Undefined. Implement with the following snippet: + + this.Then(/^create a summarized Event for Message$/, function (callback) { + // Write code here that turns the phrase above into concrete actions + callback(null, 'pending'); + }); + +3 scenarios (3 undefined) +18 steps (15 undefined, 3 passed) +0m00.003s + +Done. diff --git a/features/dialog/post_message.feature b/features/dialog/post_message.feature new file mode 100644 index 0000000..f5bcf95 --- /dev/null +++ b/features/dialog/post_message.feature @@ -0,0 +1,49 @@ +@dialog @receive_message +Feature: new message + All valid messages + should be captured in their raw form + persisted + and then denorm'd to all related services + + Why: + - we can run sentiment models on user's text to evaluate their state of mind + - in the future, we will likely get in the intent business ourselves. having the raw data will be useful. + - in any consumer analytics environment, hold on to ALL the data you can, for as LONG as you can. + + Rules: + - the inbound message must containt a bot key (which kong decodes to org and botId) as well as p/pId + + Background: + Given there are Identity records as follows: + | identityKey | + | TIN_RECORD | + | BRONZE_RECORD | + | GOLD_RECORD | + And there are Dialog records as follows: + | dialogKey | + | DIALOG_RECORD | + + @acceptance @valid_message_received + Scenario: Received valid message from existing user for active dialog + When a valid new message is received for an existing user who is actively dialoging + Then save the Message + And update Dialog with Message + And update Identity with Message + And create a summarized Event for Message + + @acceptance @valid_message_received + Scenario: Received valid message from existing user for new dialog + When a valid new message is received for an existing user starting a new dialog + Then save the Message + And update Dialog with Message + And update Identity with Message + And create a summarized Event for Message + + @acceptance @valid_message_received + Scenario: Received valid message from new user + When a valid new message is received from a new user + Then save the Message + And update Dialog with Message + And update Identity with Message + And create a summarized Event for Message + \ No newline at end of file diff --git a/features/dialog/step_definition.js b/features/dialog/step_definition.js new file mode 100644 index 0000000..7acef7f --- /dev/null +++ b/features/dialog/step_definition.js @@ -0,0 +1,77 @@ +'use strict'; + +var expect = require('chai').expect; +var identifier = null; +var restFactory = require("../../rest_factory"); + +// Public (Kong) Api: +// https://api.utu.ai/v1/message +// header: +// apiKey: 'xxxxx' +// body: +// { +// "platform": "sms", +// "platformId": "123-123-1234", +// "terms": [ +// {"term1": "term1", "prob": ".55"}, +// {"term2": "term2", "prob": ".45"}, +// ], +// "rawMessage": { +// "body": "stufff...", +// "text": "stufff...", +// }, +// "message": "green eggs and ham" +// } + +module.exports = function() { + + this.Given(/^there are Identity records as follows:$/, function (table) { + checkWhetherRecordsPresent(); + }); + + this.Given(/^there are Dialog records as follows:$/, function (table) { + checkWhetherRecordsPresent(); + }); + + var checkWhetherRecordsPresent = function(){ + // Call the mongoDB and check whether the table contents are present in the database MongoDB utility + // If not, insert the contents into the database + // then validate true to complete this step. + }; + + this.When(/^a valid new message is received for an existing user who is actively dialoging$/, function (callback) { + // Write code here that turns the phrase above into concrete actions + callback(null, 'pending'); + }); + + this.Then(/^save the Message$/, function (callback) { + // Write code here that turns the phrase above into concrete actions + callback(null, 'pending'); + }); + + this.Then(/^update Dialog with Message$/, function (callback) { + // Write code here that turns the phrase above into concrete actions + callback(null, 'pending'); + }); + + this.Then(/^update Identity with Message$/, function (callback) { + // Write code here that turns the phrase above into concrete actions + callback(null, 'pending'); + }); + + this.Then(/^create a summarized Event for Message$/, function (callback) { + // Write code here that turns the phrase above into concrete actions + callback(null, 'pending'); + }); + + this.When(/^a valid new message is received for an existing user starting a new dialog$/, function (callback) { + // Write code here that turns the phrase above into concrete actions + callback(null, 'pending'); + }); + + this.When(/^a valid new message is received from a new user$/, function (callback) { + // Write code here that turns the phrase above into concrete actions + callback(null, 'pending'); + }); + +}; diff --git a/event/post_event.feature b/features/event/post_event.feature similarity index 85% rename from event/post_event.feature rename to features/event/post_event.feature index be1fea9..566b948 100644 --- a/event/post_event.feature +++ b/features/event/post_event.feature @@ -12,7 +12,7 @@ Feature: new event Rules: - Every event must be associated to a singular identity and session - + Background: Given there are Identity records as follows: | identityKey | @@ -22,6 +22,6 @@ Feature: new event @acceptance @valid_event_received Scenario: Valid event received - When a valid new event is received - Then save the event - And update Identity + When a valid new Event is received + Then save the Event + And update Identity with Event diff --git a/features/event/step_definition.js b/features/event/step_definition.js new file mode 100644 index 0000000..4b824d8 --- /dev/null +++ b/features/event/step_definition.js @@ -0,0 +1,63 @@ +'use strict'; + +var expect = require('chai').expect; +var identifier = null; +var restFactory = require("../../rest_factory"); + +// Public Api: +// https://api.utu.ai/v1/track +// header: +// apiKey: 'xxxxx' +// body: +// { +// "platform": "sms", +// "platformId": "123-123-1234", +// "event": "test sms evet", +// "values": { +// "var1":"foo", +// "var2":"bar" +// } +// } + +module.exports = function() { + + this.Given(/^there are Identity records as follows:$/, function (table) { + checkWhetherRecordsPresent(); + }); + + var checkWhetherRecordsPresent = function(){ + // Call the mongoDB and check whether the table contents are present in the database MongoDB utility + // If not, insert the contents into the database + // then validate true to complete this step. + }; + + this.When(/^a valid new Event is received$/, function (callback) { + + var apiKey = "0475dbadc4cb410bbf562d605ea2cd47"; + var context = { + platform: "sms", + platformId: "123-123-1234", + event: "test sms evet", + values: { + var1: "foo", + var2: "bar" + } + }; + + restFactory.post( + "/track", + apiKey, + JSON.stringify(context), + callback() + ); + }); + + this.Then(/^save the Event$/, function () { + // Write code here that turns the phrase above into concrete actions + }); + + this.Then(/^update Identity with Event$/, function () { + // Write code here that turns the phrase above into concrete actions + }); + +}; diff --git a/event/swagger.json b/features/event/swagger.json similarity index 100% rename from event/swagger.json rename to features/event/swagger.json diff --git a/features/identity/alias_identity.feature b/features/identity/alias_identity.feature new file mode 100644 index 0000000..072eea9 --- /dev/null +++ b/features/identity/alias_identity.feature @@ -0,0 +1,25 @@ +@identity @identity_post +Feature: alias identity + One off condition. Used when a known foreignId wants to be applied + directly against a known tin (a.k.a. identityId). + + Why: + - Cross linking match keys is one of the most important things we can do. + + Rules: + - ... + +Background: + Given there are Identity records as follows: + | identityKey | + | TIN_RECORD | + | BRONZE_RECORD | + | GOLD_RECORD | + +@acceptance +Scenario: Alias called for a known identity + When an aliased foreignId is received + Then review medal match when upserting an Identity tin record + And push update to all medal Identity views + And push impacted Identity rollup to related services + \ No newline at end of file diff --git a/identity/get_identity.feature b/features/identity/get_identity.feature similarity index 87% rename from identity/get_identity.feature rename to features/identity/get_identity.feature index 14aeb80..582d8f3 100644 --- a/identity/get_identity.feature +++ b/features/identity/get_identity.feature @@ -9,8 +9,7 @@ Feature: Search identity - ... Background: - Given there are Identity records as follows: - all requests are scoped to a specific botId + Given there are Identity records as follows # these are probably a REALLY good example as when to use examples? @acceptance diff --git a/features/identity/post_ident.log b/features/identity/post_ident.log new file mode 100644 index 0000000..a11bc96 --- /dev/null +++ b/features/identity/post_ident.log @@ -0,0 +1,243 @@ +Running "jshint:all" (jshint) task +>> 1 file lint free. + +Running "exec:run_cucumber_tests" (exec) task +@identity @identity_post +Feature: upsert identity + + Whenever data is received about a user + whether from external source + or from other internal process + it should be upserted + to the proper, medaled user / identity record + + Why: + - What we know about users underpins the ability to respond to them + + Rules: + - ... + + @for_testing @acceptance @for_testing + Scenario: Update received for Identity "custom" field + Given there are Identity records as follows: + | identityKey  | + | TIN_RECORD  | + | BRONZE_RECORD | + | GOLD_RECORD  | + When an Identity update is received for a non-matching field + Then upsert an Identity tin record + And push update to all medal Identity views + And push Identity rollup to related services + + @for_testing @identity @identity_post + Scenario Outline: Updare received for Identity "match" field + Given there are Identity records as follows: + | identityKey  | + | TIN_RECORD  | + | BRONZE_RECORD | + | GOLD_RECORD  | + When an Identity update is received with email + Then review medal match when upserting an Identity tin record + And push update to all medal Identity views + And push impacted Identity rollup to related services + + @for_testing @identity @identity_post + Scenario Outline: Updare received for Identity "match" field + Given there are Identity records as follows: + | identityKey  | + | TIN_RECORD  | + | BRONZE_RECORD | + | GOLD_RECORD  | + When an Identity update is received with phone + first + Then review medal match when upserting an Identity tin record + And push update to all medal Identity views + And push impacted Identity rollup to related services + + @for_testing @identity @identity_post + Scenario Outline: Updare received for Identity "match" field + Given there are Identity records as follows: + | identityKey  | + | TIN_RECORD  | + | BRONZE_RECORD | + | GOLD_RECORD  | + When an Identity update is received with browserId + Then review medal match when upserting an Identity tin record + And push update to all medal Identity views + And push impacted Identity rollup to related services + + @for_testing @identity @identity_post + Scenario Outline: Updare received for Identity "match" field + Given there are Identity records as follows: + | identityKey  | + | TIN_RECORD  | + | BRONZE_RECORD | + | GOLD_RECORD  | + When an Identity update is received with p + pid + Then review medal match when upserting an Identity tin record + And push update to all medal Identity views + And push impacted Identity rollup to related services + + @for_testing @identity @identity_post + Scenario Outline: Updare received for Identity "match" field + Given there are Identity records as follows: + | identityKey  | + | TIN_RECORD  | + | BRONZE_RECORD | + | GOLD_RECORD  | + When an Identity update is received with foreignId + Then review medal match when upserting an Identity tin record + And push update to all medal Identity views + And push impacted Identity rollup to related services + +Failures: + +1) Background: + Step: Given there are Identity records as follows: - features/identity/post_identity.feature:17 + Message: + Multiple step definitions match: + /^there are Identity records as follows:$/ - features/dialog/step_definition.js:28 + /^there are Identity records as follows:$/ - features/event/step_definition.js:24 + /^there are Identity records as follows:$/ - features/identity/step_definition.js:24 + +2) Background: + Step: Given there are Identity records as follows: - features/identity/post_identity.feature:17 + Message: + Multiple step definitions match: + /^there are Identity records as follows:$/ - features/dialog/step_definition.js:28 + /^there are Identity records as follows:$/ - features/event/step_definition.js:24 + /^there are Identity records as follows:$/ - features/identity/step_definition.js:24 + +3) Background: + Step: Given there are Identity records as follows: - features/identity/post_identity.feature:17 + Message: + Multiple step definitions match: + /^there are Identity records as follows:$/ - features/dialog/step_definition.js:28 + /^there are Identity records as follows:$/ - features/event/step_definition.js:24 + /^there are Identity records as follows:$/ - features/identity/step_definition.js:24 + +4) Background: + Step: Given there are Identity records as follows: - features/identity/post_identity.feature:17 + Message: + Multiple step definitions match: + /^there are Identity records as follows:$/ - features/dialog/step_definition.js:28 + /^there are Identity records as follows:$/ - features/event/step_definition.js:24 + /^there are Identity records as follows:$/ - features/identity/step_definition.js:24 + +5) Background: + Step: Given there are Identity records as follows: - features/identity/post_identity.feature:17 + Message: + Multiple step definitions match: + /^there are Identity records as follows:$/ - features/dialog/step_definition.js:28 + /^there are Identity records as follows:$/ - features/event/step_definition.js:24 + /^there are Identity records as follows:$/ - features/identity/step_definition.js:24 + +6) Background: + Step: Given there are Identity records as follows: - features/identity/post_identity.feature:17 + Message: + Multiple step definitions match: + /^there are Identity records as follows:$/ - features/dialog/step_definition.js:28 + /^there are Identity records as follows:$/ - features/event/step_definition.js:24 + /^there are Identity records as follows:$/ - features/identity/step_definition.js:24 + +Warnings: + +1) Scenario: Updare received for Identity "match" field - features/identity/post_identity.feature:39 + Step: When an Identity update is received with email - features/identity/post_identity.feature:32 + Message: + Undefined. Implement with the following snippet: + + this.When(/^an Identity update is received with (.*)$/, function (matchField, callback) { + // Write code here that turns the phrase above into concrete actions + callback(null, 'pending'); + }); + +2) Scenario: Updare received for Identity "match" field - features/identity/post_identity.feature:39 + Step: Then review medal match when upserting an Identity tin record - features/identity/post_identity.feature:33 + Message: + Undefined. Implement with the following snippet: + + this.Then(/^review medal match when upserting an Identity tin record$/, function (callback) { + // Write code here that turns the phrase above into concrete actions + callback(null, 'pending'); + }); + +3) Scenario: Updare received for Identity "match" field - features/identity/post_identity.feature:39 + Step: And push impacted Identity rollup to related services - features/identity/post_identity.feature:35 + Message: + Undefined. Implement with the following snippet: + + this.Then(/^push impacted Identity rollup to related services$/, function (callback) { + // Write code here that turns the phrase above into concrete actions + callback(null, 'pending'); + }); + +4) Scenario: Updare received for Identity "match" field - features/identity/post_identity.feature:40 + Step: When an Identity update is received with phone + first - features/identity/post_identity.feature:32 + Message: + Undefined. Implement with the following snippet: + + this.When(/^an Identity update is received with (.*)$/, function (matchField, callback) { + // Write code here that turns the phrase above into concrete actions + callback(null, 'pending'); + }); + +5) Scenario: Updare received for Identity "match" field - features/identity/post_identity.feature:40 + Step: Then review medal match when upserting an Identity tin record - features/identity/post_identity.feature:33 + Message: + Undefined. Implement with the following snippet: + + this.Then(/^review medal match when upserting an Identity tin record$/, function (callback) { + // Write code here that turns the phrase above into concrete actions + callback(null, 'pending'); + }); + +6) Scenario: Updare received for Identity "match" field - features/identity/post_identity.feature:40 + Step: And push impacted Identity rollup to related services - features/identity/post_identity.feature:35 + Message: + Undefined. Implement with the following snippet: + + this.Then(/^push impacted Identity rollup to related services$/, function (callback) { + // Write code here that turns the phrase above into concrete actions + callback(null, 'pending'); + }); + +7) Scenario: Updare received for Identity "match" field - features/identity/post_identity.feature:41 + Step: When an Identity update is received with browserId - features/identity/post_identity.feature:32 + Message: + Undefined. Implement with the following snippet: + + this.When(/^an Identity update is received with (.*)$/, function (matchField, callback) { + // Write code here that turns the phrase above into concrete actions + callback(null, 'pending'); + }); + +8) Scenario: Updare received for Identity "match" field - features/identity/post_identity.feature:41 + Step: Then review medal match when upserting an Identity tin record - features/identity/post_identity.feature:33 + Message: + Undefined. Implement with the following snippet: + + this.Then(/^review medal match when upserting an Identity tin record$/, function (callback) { + // Write code here that turns the phrase above into concrete actions + callback(null, 'pending'); + }); + +9) Scenario: Updare received for Identity "match" field - features/identity/post_identity.feature:41 + Step: And push impacted Identity rollup to related services - features/identity/post_identity.feature:35 + Message: + Undefined. Implement with the following snippet: + + this.Then(/^push impacted Identity rollup to related services$/, function (callback) { + // Write code here that turns the phrase above into concrete actions + callback(null, 'pending'); + }); + +10) Scenario: Updare received for Identity "match" field - features/identity/post_identity.feature:42 + Step: When an Identity update is received with p + pid - features/identity/post_identity.feature:32 + Message: + Undefined. Implement with the following snippet: + + this.When(/^an Identity update is received with (.*)$/, function (matchField, callback) { + // Write code>> Exited with code: 1. +Warning: Task "exec:run_cucumber_tests" failed. Use --force to continue. + +Aborted due to warnings. diff --git a/features/identity/post_identity.feature b/features/identity/post_identity.feature new file mode 100644 index 0000000..c2d7acd --- /dev/null +++ b/features/identity/post_identity.feature @@ -0,0 +1,43 @@ +@identity @identity_post +Feature: upsert identity + Whenever data is received about a user + whether from external source + or from other internal process + it should be upserted + to the proper, medaled user / identity record + + Why: + - What we know about users underpins the ability to respond to them + + Rules: + - ... + +@for_testing +Background: + Given there are Identity records as follows: + | identityKey | + | TIN_RECORD | + | BRONZE_RECORD | + | GOLD_RECORD | + +@acceptance @for_testing +Scenario: Update received for Identity "custom" field + When an Identity update is received for a non-matching field + Then upsert an Identity tin record + And push update to all medal Identity views + And push Identity rollup to related services + +@for_testing +Scenario Outline: Updare received for Identity "match" field + When an Identity update is received with + Then review medal match when upserting an Identity tin record + And push update to all medal Identity views + And push impacted Identity rollup to related services + + Examples: + | matchField | + | email | + | phone + first | + | browserId | + | p + pid | + | foreignId | diff --git a/features/identity/step_definition.js b/features/identity/step_definition.js new file mode 100644 index 0000000..b220283 --- /dev/null +++ b/features/identity/step_definition.js @@ -0,0 +1,64 @@ +'use strict'; + +var expect = require('chai').expect; +var identifier = null; +var restFactory = require("../../rest_factory"); + +// Public Api: +// https://api.utu.ai/v1/identity/'+platform+'/'+platformId +// header: +// apiKey: 'xxxxx' +// body: +// { +// "platform": "sms", +// "platformId": "123-123-1234", +// "custom": { +// "var1":"foo", +// "var2":"bar" +// } +// } + +module.exports = function() { + + this.Given(/^there are Identity records as follows:$/, function (table) { + checkWhetherRecordsPresent(); + }); + + var checkWhetherRecordsPresent = function(){ + // Call the mongoDB and check whether the table contents are present in the database MongoDB utility + // If not, insert the contents into the database + // then validate true to complete this step. + }; + + this.When(/^an Identity update is received for a non\-matching field$/, function (callback) { + // Write code here that turns the phrase above into concrete actions + callback(null, 'pending'); + }); + + this.Then(/^upsert an Identity tin record$/, function () { + // Write code here that turns the phrase above into concrete actions + }); + + this.Then(/^push update to all medal Identity views$/, function () { + // Write code here that turns the phrase above into concrete actions + }); + + this.Then(/^push Identity rollup to related services$/, function (callback) { + // Write code here that turns the phrase above into concrete actions + callback(null, 'pending'); + }); + + this.When(/^an Identity update is received with (.*)$/, function (matchField, callback) { + // Write code here that turns the phrase above into concrete actions + callback(null, 'pending'); + }); + + this.Then(/^review medal match when upserting an Identity tin record$/, function () { + // Write code here that turns the phrase above into concrete actions + }); + + this.Then(/^push impacted Identity rollup to related services$/, function () { + // Write code here that turns the phrase above into concrete actions + }); + +}; diff --git a/identity/post_identity.feature b/identity/post_identity.feature deleted file mode 100644 index c2e5357..0000000 --- a/identity/post_identity.feature +++ /dev/null @@ -1,47 +0,0 @@ -@identity @identity_post -Feature: Update identity - ... - - Why: - - ... - - Rules: - - ... - - Background: - Given there are Identity records as follows: - - - @acceptance - Scenario: Update received for non-match field - Given - When an update is received for a non-matching field, like: - | lastName | Gender | Birthday | - Then the corresponding tin record should be updated - And the corresponding bronze record should be updated - And the corresponding silver record should be updated - And the corresponding gold record should be updated - - @acceptance - Scenario: Update received including an email - Given - When - Then save the message - - @acceptance - Scenario: Update received including a first name or phone - Given - When - Then save the message - - @acceptance - Scenario: Update received including a foreignId - Given - When - Then save the message - - @acceptance - Scenario: Update received including a browserId - Given - When - Then save the message \ No newline at end of file diff --git a/package.json b/package.json new file mode 100644 index 0000000..7145af2 --- /dev/null +++ b/package.json @@ -0,0 +1,28 @@ +{ + "name": "cucumber-js-selenium-webdriver-example", + "version": "0.0.1", + "description": "A starter for acceptance testing using cucumber-js and webdriver-js.", + "repository": { + "type": "git", + "url": "git@github.com:Matt-B/cucumber-js-selenium-webdriver-example.git" + }, + "scripts": { + "start": "SET NODE_ENV=dev && node server.js", + "test": "node_modules/grunt-cli/bin/grunt" + }, + "devDependencies": { + "cucumber": "^0.10.2", + "selenium-webdriver": "^2.53.2", + "chai": "^3.5.0", + "grunt": "^1.0.1", + "grunt-cli": "^1.2.0", + "grunt-contrib-jshint": "^1.0.0", + "grunt-exec": "^0.4.7", + "grunt-env": "^0.4.4", + "sanitize-filename": "^1.6.0", + "rest-assured":"^0.1.0", + "cucumber-html-reporter":"^2.0.3", + "JSONPath": "~0.9.1", + "request": "~2.27.0" + } +} \ No newline at end of file diff --git a/rest_factory.js b/rest_factory.js new file mode 100644 index 0000000..cb5f676 --- /dev/null +++ b/rest_factory.js @@ -0,0 +1,95 @@ +'use strict'; + +var request = require('request'); + +var configuration = require('./configuration'); + +var restFactory = function restFactory(callback) { + + var self = this; + + this.lastResponse = null; + + this.get = function(path, callback) { + var uri = this.uri(path) + request.get({url: uri, headers: {'User-Agent': 'request'}}, + function(error, response) { + if (error) { + return callback.fail(new Error('Error on GET request to ' + uri + + ': ' + error.message)) + } + self.lastResponse = response; + callback(); + }) + } + + this.post = function(path, apiKey, requestBody, callback) { + var uri = this.uri(path) + request({ + url: uri, + body: requestBody, + method: 'POST', + headers: {'User-Agent': 'request', + apiKey + } + }, + function(error, response) { + if (error) { + return callback(new Error('Error on POST request to ' + uri + ': ' + + error.message)); + } + self.lastResponse = response; + callback(null, self.lastResponse.headers.location); + } + ) + } + + this.put = function(path, requestBody, callback) { + var uri = this.uri(path) + request({url: uri, body: requestBody, method: 'PUT', + headers: {'User-Agent': 'request'}}, + function(error, response) { + if (error) { + return callback(new Error('Error on PUT request to ' + uri + ': ' + + error.message)); + } + self.lastResponse = response; + callback(null, self.lastResponse.headers.locations); + }) + } + + this.delete = function(path, callback) { + var uri = this.uri(path); + request({url: uri, method: 'DELETE'}, + function(error, response) { + if (error) { + return callback(new Error('Error on DELETE request to ' + uri + ': ' + + error.message)); + } + self.lastResponse = response; + callback(); + }) + } + + this.options = function(path, callback) { + var uri = this.uri(path) + request({'uri': uri, method: 'OPTIONS', + headers: {'User-Agent': 'request'}}, + function(error, response) { + if (error) { + return callback.fail(new Error('Error on OPTIONS request to ' + uri + + ': ' + error.message)) + } + self.lastResponse = response; + callback(); + }) + } + + this.uri = function(path) { + return configuration.BASE_URL + path; + } + + callback(); +} + +exports.restFactory = restFactory; diff --git a/web_factory.js b/web_factory.js new file mode 100644 index 0000000..81d7a99 --- /dev/null +++ b/web_factory.js @@ -0,0 +1,52 @@ +'use strict'; + +var fs = require('fs'); +var webdriver = require('selenium-webdriver'); +var platform = process.env.PLATFORM || "CHROME"; + +var buildChromeDriver = function() { + return new webdriver.Builder(). + withCapabilities(webdriver.Capabilities.chrome()). + build(); +}; + +var buildFirefoxDriver = function() { + return new webdriver.Builder(). + withCapabilities(webdriver.Capabilities.firefox()). + build(); +}; + +switch(platform) { + case 'FIREFOX': + var driver = buildFirefoxDriver(); + break; + default: + var driver = buildChromeDriver(); +} + +var getDriver = function() { + return driver; +}; + +var webFactory = function webFactory() { + + var defaultTimeout = 20000; + var screenshotPath = "screenshots"; + + this.webdriver = webdriver; + this.driver = driver; + + if(!fs.existsSync(screenshotPath)) { + fs.mkdirSync(screenshotPath); + } + + this.waitFor = function(cssLocator, timeout) { + var waitTimeout = timeout || defaultTimeout; + return driver.wait(function() { + return driver.isElementPresent({ css: cssLocator }); + }, waitTimeout); + }; +}; + +module.exports.webFactory = webFactory; +module.exports.getDriver = getDriver; \ No newline at end of file