diff --git a/.kokoro/build.sh b/.kokoro/build.sh
index 8b91dc6512..167259647f 100755
--- a/.kokoro/build.sh
+++ b/.kokoro/build.sh
@@ -45,7 +45,12 @@ export SENDGRID_API_KEY=$(cat $KOKORO_GFILE_DIR/secrets-sendgrid-api-key.txt)
 export FUNCTIONS_TOPIC=integration-tests-instance
 export FUNCTIONS_BUCKET=$GCLOUD_PROJECT
 export OUTPUT_BUCKET=$FUNCTIONS_BUCKET
+
+#  functions/translate
 export SUPPORTED_LANGUAGE_CODES="en,es"
+export TRANSLATE_TOPIC=$FUNCTIONS_TOPIC
+export RESULT_TOPIC=$FUNCTIONS_TOPIC
+export RESULT_BUCKET=$FUNCTIONS_BUCKET
 
 # Configure IoT variables
 export NODEJS_IOT_EC_PUBLIC_KEY=${KOKORO_GFILE_DIR}/ec_public.pem
diff --git a/functions/ocr/app/index.js b/functions/ocr/app/index.js
index c685ad78cd..bf1fdfa1e5 100644
--- a/functions/ocr/app/index.js
+++ b/functions/ocr/app/index.js
@@ -1,5 +1,5 @@
 /**
- * Copyright 2016, Google, Inc.
+ * Copyright 2019, Google LLC.
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
@@ -16,7 +16,12 @@
 'use strict';
 
 // [START functions_ocr_setup]
-const config = require('./config.json');
+const config = require('nconf')
+  .env()
+  .file('./config.json')
+  .defaults({
+    TO_LANG: ['en', 'es'],
+  });
 
 // Get a reference to the Pub/Sub component
 const {PubSub} = require('@google-cloud/pubsub');
@@ -43,14 +48,12 @@ const {Buffer} = require('safe-buffer');
  * @param {string} topicName Name of the topic on which to publish.
  * @param {object} data The message data to publish.
  */
-function publishResult(topicName, data) {
+const publishResult = async (topicName, data) => {
   const dataBuffer = Buffer.from(JSON.stringify(data));
 
-  return pubsub
-    .topic(topicName)
-    .get({autoCreate: true})
-    .then(([topic]) => topic.publish(dataBuffer));
-}
+  const [topic] = await pubsub.topic(topicName).get({autoCreate: true});
+  topic.publish(dataBuffer);
+};
 // [END functions_ocr_publish]
 
 // [START functions_ocr_detect]
@@ -61,42 +64,38 @@ function publishResult(topicName, data) {
  * @param {string} filename Cloud Storage file name.
  * @returns {Promise}
  */
-function detectText(bucketName, filename) {
-  let text;
-
+const detectText = async (bucketName, filename) => {
   console.log(`Looking for text in image ${filename}`);
-  return vision
-    .textDetection(`gs://${bucketName}/${filename}`)
-    .then(([detections]) => {
-      const annotation = detections.textAnnotations[0];
-      text = annotation ? annotation.description : '';
-      console.log(`Extracted text from image (${text.length} chars)`);
-      return translate.detect(text);
-    })
-    .then(([detection]) => {
-      if (Array.isArray(detection)) {
-        detection = detection[0];
-      }
-      console.log(`Detected language "${detection.language}" for ${filename}`);
-
-      // Submit a message to the bus for each language we're going to translate to
-      const tasks = config.TO_LANG.map(lang => {
-        let topicName = config.TRANSLATE_TOPIC;
-        if (detection.language === lang) {
-          topicName = config.RESULT_TOPIC;
-        }
-        const messageData = {
-          text: text,
-          filename: filename,
-          lang: lang,
-        };
-
-        return publishResult(topicName, messageData);
-      });
-
-      return Promise.all(tasks);
-    });
-}
+  const [textDetections] = await vision.textDetection(
+    `gs://${bucketName}/${filename}`
+  );
+  const [annotation] = textDetections.textAnnotations;
+  const text = annotation ? annotation.description : '';
+  console.log(`Extracted text from image:`, text);
+
+  let [translateDetection] = await translate.detect(text);
+  if (Array.isArray(translateDetection)) {
+    [translateDetection] = translateDetection;
+  }
+  console.log(
+    `Detected language "${translateDetection.language}" for ${filename}`
+  );
+
+  // Submit a message to the bus for each language we're going to translate to
+  const topicName = config.get('TRANSLATE_TOPIC');
+
+  const tasks = config.get('TO_LANG').map(lang => {
+    const messageData = {
+      text: text,
+      filename: filename,
+      lang: lang,
+    };
+
+    return publishResult(topicName, messageData);
+  });
+
+  return Promise.all(tasks);
+};
 // [END functions_ocr_detect]
 
 // [START functions_ocr_rename]
@@ -107,9 +106,9 @@ function detectText(bucketName, filename) {
  * @param {string} lang Language to append.
  * @returns {string} The new filename.
  */
-function renameImageForSave(filename, lang) {
+const renameImageForSave = (filename, lang) => {
   return `${filename}_to_${lang}.txt`;
-}
+};
 // [END functions_ocr_rename]
 
 // [START functions_ocr_process]
@@ -118,35 +117,24 @@ function renameImageForSave(filename, lang) {
  * a file is uploaded to the Cloud Storage bucket you created
  * for uploading images.
  *
- * @param {object} event.data (Node 6) A Google Cloud Storage File object.
- * @param {object} event (Node 8+) A Google Cloud Storage File object.
+ * @param {object} event A Google Cloud Storage File object.
  */
-exports.processImage = event => {
-  const file = event.data || event;
-
-  return Promise.resolve()
-    .then(() => {
-      if (file.resourceState === 'not_exists') {
-        // This was a deletion event, we don't want to process this
-        return;
-      }
-
-      if (!file.bucket) {
-        throw new Error(
-          'Bucket not provided. Make sure you have a "bucket" property in your request'
-        );
-      }
-      if (!file.name) {
-        throw new Error(
-          'Filename not provided. Make sure you have a "name" property in your request'
-        );
-      }
-
-      return detectText(file.bucket, file.name);
-    })
-    .then(() => {
-      console.log(`File ${file.name} processed.`);
-    });
+exports.processImage = async event => {
+  const {bucket, name} = event;
+
+  if (!bucket) {
+    throw new Error(
+      'Bucket not provided. Make sure you have a "bucket" property in your request'
+    );
+  }
+  if (!name) {
+    throw new Error(
+      'Filename not provided. Make sure you have a "name" property in your request'
+    );
+  }
+
+  await detectText(bucket, name);
+  console.log(`File ${name} processed.`);
 };
 // [END functions_ocr_process]
 
@@ -157,49 +145,44 @@ exports.processImage = event => {
  * by the TRANSLATE_TOPIC value in the config.json file. The
  * function translates text using the Google Translate API.
  *
- * @param {object} event.data (Node 6) The Cloud Pub/Sub Message object.
- * @param {object} event (Node 8+) The Cloud Pub/Sub Message object.
+ * @param {object} event The Cloud Pub/Sub Message object.
  * @param {string} {messageObject}.data The "data" property of the Cloud Pub/Sub
  * Message. This property will be a base64-encoded string that you must decode.
  */
-exports.translateText = event => {
-  const pubsubData = event.data.data || event.data;
+exports.translateText = async event => {
+  const pubsubData = event.data;
   const jsonStr = Buffer.from(pubsubData, 'base64').toString();
-  const payload = JSON.parse(jsonStr);
-
-  return Promise.resolve()
-    .then(() => {
-      if (!payload.text) {
-        throw new Error(
-          'Text not provided. Make sure you have a "text" property in your request'
-        );
-      }
-      if (!payload.filename) {
-        throw new Error(
-          'Filename not provided. Make sure you have a "filename" property in your request'
-        );
-      }
-      if (!payload.lang) {
-        throw new Error(
-          'Language not provided. Make sure you have a "lang" property in your request'
-        );
-      }
-
-      console.log(`Translating text into ${payload.lang}`);
-      return translate.translate(payload.text, payload.lang);
-    })
-    .then(([translation]) => {
-      const messageData = {
-        text: translation,
-        filename: payload.filename,
-        lang: payload.lang,
-      };
-
-      return publishResult(config.RESULT_TOPIC, messageData);
-    })
-    .then(() => {
-      console.log(`Text translated to ${payload.lang}`);
-    });
+  const {text, filename, lang} = JSON.parse(jsonStr);
+
+  if (!text) {
+    throw new Error(
+      'Text not provided. Make sure you have a "text" property in your request'
+    );
+  }
+  if (!filename) {
+    throw new Error(
+      'Filename not provided. Make sure you have a "filename" property in your request'
+    );
+  }
+  if (!lang) {
+    throw new Error(
+      'Language not provided. Make sure you have a "lang" property in your request'
+    );
+  }
+
+  console.log(`Translating text into ${lang}`);
+  const [translation] = await translate.translate(text, lang);
+
+  console.log(`Translated text:`, translation);
+
+  const messageData = {
+    text: translation,
+    filename: filename,
+    lang: lang,
+  };
+
+  await publishResult(config.get('RESULT_TOPIC'), messageData);
+  console.log(`Text translated to ${lang}`);
 };
 // [END functions_ocr_translate]
 
@@ -210,46 +193,40 @@ exports.translateText = event => {
  * by the RESULT_TOPIC value in the config.json file. The
  * function saves the data packet to a file in GCS.
  *
- * @param {object} event.data (Node 6) The Cloud Pub/Sub Message object.
- * @param {object} event (Node 8+) The Cloud Pub/Sub Message object.
+ * @param {object} event The Cloud Pub/Sub Message object.
  * @param {string} {messageObject}.data The "data" property of the Cloud Pub/Sub
  * Message. This property will be a base64-encoded string that you must decode.
  */
-exports.saveResult = event => {
-  const pubsubData = event.data.data || event.data;
+exports.saveResult = async event => {
+  const pubsubData = event.data;
   const jsonStr = Buffer.from(pubsubData, 'base64').toString();
-  const payload = JSON.parse(jsonStr);
-
-  return Promise.resolve()
-    .then(() => {
-      if (!payload.text) {
-        throw new Error(
-          'Text not provided. Make sure you have a "text" property in your request'
-        );
-      }
-      if (!payload.filename) {
-        throw new Error(
-          'Filename not provided. Make sure you have a "filename" property in your request'
-        );
-      }
-      if (!payload.lang) {
-        throw new Error(
-          'Language not provided. Make sure you have a "lang" property in your request'
-        );
-      }
-
-      console.log(`Received request to save file ${payload.filename}`);
-
-      const bucketName = config.RESULT_BUCKET;
-      const filename = renameImageForSave(payload.filename, payload.lang);
-      const file = storage.bucket(bucketName).file(filename);
-
-      console.log(`Saving result to ${filename} in bucket ${bucketName}`);
-
-      return file.save(payload.text);
-    })
-    .then(() => {
-      console.log(`File saved.`);
-    });
+  const {text, filename, lang} = JSON.parse(jsonStr);
+
+  if (!text) {
+    throw new Error(
+      'Text not provided. Make sure you have a "text" property in your request'
+    );
+  }
+  if (!filename) {
+    throw new Error(
+      'Filename not provided. Make sure you have a "filename" property in your request'
+    );
+  }
+  if (!lang) {
+    throw new Error(
+      'Language not provided. Make sure you have a "lang" property in your request'
+    );
+  }
+
+  console.log(`Received request to save file ${filename}`);
+
+  const bucketName = config.get('RESULT_BUCKET');
+  const newFilename = renameImageForSave(filename, lang);
+  const file = storage.bucket(bucketName).file(newFilename);
+
+  console.log(`Saving result to ${newFilename} in bucket ${bucketName}`);
+
+  await file.save(text);
+  console.log(`File saved.`);
 };
 // [END functions_ocr_save]
diff --git a/functions/ocr/app/package.json b/functions/ocr/app/package.json
index fd9bb18cf4..d21cea3e35 100644
--- a/functions/ocr/app/package.json
+++ b/functions/ocr/app/package.json
@@ -19,16 +19,21 @@
     "@google-cloud/storage": "^2.3.3",
     "@google-cloud/translate": "^3.0.0",
     "@google-cloud/vision": "^0.25.0",
+    "nconf": "^0.10.0",
     "safe-buffer": "^5.1.2"
   },
   "devDependencies": {
-     "@google-cloud/nodejs-repo-tools": "^3.3.0",
-    "mocha": "^6.0.0",
-    "proxyquire": "^2.1.0",
-    "sinon": "^7.2.7"
+    "@google-cloud/nodejs-repo-tools": "^3.3.0",
+    "mocha": "^6.0.0"
   },
   "cloud-repo-tools": {
     "requiresKeyFile": true,
-    "requiresProjectId": true
+    "requiresProjectId": true,
+    "requiredEnvVars": [
+      "FUNCTIONS_BUCKET",
+      "OUTPUT_BUCKET",
+      "TRANSLATE_TOPIC",
+      "RESULT_TOPIC"
+    ]
   }
 }
diff --git a/functions/ocr/app/test/index.test.js b/functions/ocr/app/test/index.test.js
index dfabf5673c..5840e148cd 100644
--- a/functions/ocr/app/test/index.test.js
+++ b/functions/ocr/app/test/index.test.js
@@ -1,5 +1,5 @@
 /**
- * Copyright 2017, Google, Inc.
+ * Copyright 2019, Google LLC.
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
@@ -15,232 +15,72 @@
 
 'use strict';
 
-const proxyquire = require('proxyquire').noCallThru();
-const sinon = require('sinon');
 const assert = require('assert');
-const tools = require('@google-cloud/nodejs-repo-tools');
 const {Buffer} = require('safe-buffer');
 
-const bucketName = 'my-bucket';
-const filename = 'image.jpg';
-const text = 'text';
-const lang = 'lang';
-const translation = 'translation';
-
-function getSample() {
-  const config = {
-    RESULT_TOPIC: 'result-topic',
-    RESULT_BUCKET: 'result-bucket',
-    TRANSLATE_TOPIC: 'translate-topic',
-    TO_LANG: ['en', 'fr', 'es', 'ja', 'ru'],
-  };
-  const topic = {
-    publish: sinon.stub().returns(Promise.resolve([])),
-  };
-  topic.get = sinon.stub().returns(Promise.resolve([topic]));
-  topic.publisher = sinon.stub().returns(topic);
-
-  const file = {
-    save: sinon.stub().returns(Promise.resolve([])),
-    bucket: bucketName,
-    name: filename,
-  };
-  const bucket = {
-    file: sinon.stub().returns(file),
-  };
-  const pubsubMock = {
-    topic: sinon.stub().returns(topic),
-  };
-  const storageMock = {
-    bucket: sinon.stub().returns(bucket),
-  };
-  const visionMock = {
-    textDetection: sinon
-      .stub()
-      .returns(Promise.resolve([{textAnnotations: [{description: text}]}])),
-  };
-  const translateMock = {
-    detect: sinon.stub().returns(Promise.resolve([{language: 'ja'}])),
-    translate: sinon.stub().returns(Promise.resolve([translation])),
-  };
-
-  const PubsubMock = sinon.stub().returns(pubsubMock);
-  const StorageMock = sinon.stub().returns(storageMock);
-
-  const stubConstructor = (packageName, property, mocks) => {
-    let stubInstance = sinon.createStubInstance(
-      require(packageName)[property],
-      mocks
-    );
-    stubInstance = Object.assign(stubInstance, mocks);
+const {Storage} = require('@google-cloud/storage');
+const storage = new Storage();
 
-    const out = {};
-    out[property] = sinon.stub().returns(stubInstance);
-    return out;
-  };
+const tools = require('@google-cloud/nodejs-repo-tools');
 
-  const visionStub = stubConstructor(
-    '@google-cloud/vision',
-    'ImageAnnotatorClient',
-    visionMock
-  );
-  const translateStub = stubConstructor(
-    '@google-cloud/translate',
-    'Translate',
-    translateMock
-  );
+const bucketName = process.env.FUNCTIONS_BUCKET;
+const filename = 'wakeupcat.jpg';
+const text = 'Wake up human!';
+const lang = 'en';
 
-  return {
-    program: proxyquire('../', {
-      '@google-cloud/translate': translateStub,
-      '@google-cloud/vision': visionStub,
-      '@google-cloud/pubsub': {PubSub: PubsubMock},
-      '@google-cloud/storage': {Storage: StorageMock},
-      './config.json': config,
-    }),
-    mocks: {
-      config,
-      pubsub: pubsubMock,
-      storage: storageMock,
-      bucket: bucket,
-      file,
-      vision: visionMock,
-      translate: translateMock,
-      topic,
-    },
-  };
-}
+const {RESULT_BUCKET} = process.env;
 
-beforeEach(tools.stubConsole);
-afterEach(tools.restoreConsole);
+const program = require('..');
 
-it('processImage does nothing on delete', async () => {
-  await getSample().program.processImage({data: {resourceState: 'not_exists'}});
-});
+const errorMsg = (name, propertyName) => {
+  propertyName = propertyName || name.toLowerCase();
+  return `${name} not provided. Make sure you have a "${propertyName}" property in your request`;
+};
 
-it('processImage fails without a bucket', async () => {
-  const error = new Error(
-    'Bucket not provided. Make sure you have a "bucket" property in your request'
-  );
-  try {
-    await getSample().program.processImage({data: {}});
-  } catch (err) {
-    assert.deepStrictEqual(err, error);
-  }
-});
+before(tools.stubConsole);
+after(tools.restoreConsole);
 
-it('processImage fails without a name', async () => {
-  const error = new Error(
-    'Filename not provided. Make sure you have a "name" property in your request'
-  );
-  try {
-    await getSample().program.processImage({data: {bucket: bucketName}});
-  } catch (err) {
-    assert.deepStrictEqual(err, error);
-  }
-});
+describe('processImage', () => {
+  it('processImage validates parameters', async () => {
+    try {
+      await program.processImage({data: {}});
+      assert.fail('no error thrown');
+    } catch (err) {
+      assert.strictEqual(err.message, errorMsg('Bucket'));
+    }
+  });
 
-it('processImage processes an image with Node 6 arguments', async () => {
-  const event = {
-    data: {
+  it('processImage detects text', async () => {
+    const data = {
       bucket: bucketName,
       name: filename,
-    },
-  };
-  const sample = getSample();
-
-  await sample.program.processImage(event);
-  assert.strictEqual(console.log.callCount, 4);
-  assert.deepStrictEqual(console.log.getCall(0).args, [
-    `Looking for text in image ${filename}`,
-  ]);
-  assert.deepStrictEqual(console.log.getCall(1).args, [
-    `Extracted text from image (${text.length} chars)`,
-  ]);
-  assert.deepStrictEqual(console.log.getCall(2).args, [
-    `Detected language "ja" for ${filename}`,
-  ]);
-  assert.deepStrictEqual(console.log.getCall(3).args, [
-    `File ${event.data.name} processed.`,
-  ]);
-});
+    };
 
-it('processImage processes an image with Node 8 arguments', async () => {
-  const data = {
-    bucket: bucketName,
-    name: filename,
-  };
-  const sample = getSample();
-
-  await sample.program.processImage(data);
-  assert.strictEqual(console.log.callCount, 4);
-  assert.deepStrictEqual(console.log.getCall(0).args, [
-    `Looking for text in image ${filename}`,
-  ]);
-  assert.deepStrictEqual(console.log.getCall(1).args, [
-    `Extracted text from image (${text.length} chars)`,
-  ]);
-  assert.deepStrictEqual(console.log.getCall(2).args, [
-    `Detected language "ja" for ${filename}`,
-  ]);
-  assert.deepStrictEqual(console.log.getCall(3).args, [
-    `File ${data.name} processed.`,
-  ]);
+    await program.processImage(data);
+    assert.ok(console.log.calledWith(`Detected language "en" for ${filename}`));
+    assert.ok(
+      console.log.calledWith(`Extracted text from image:`, `${text}\n`)
+    );
+    assert.ok(console.log.calledWith(`Detected language "en" for ${filename}`));
+    assert.ok(console.log.calledWith(`File ${filename} processed.`));
+  });
 });
 
-it('translateText fails without text', async () => {
-  const error = new Error(
-    'Text not provided. Make sure you have a "text" property in your request'
-  );
-  const event = {
-    data: {
+describe('translateText', () => {
+  it('translateText validates parameters', async () => {
+    const event = {
       data: Buffer.from(JSON.stringify({})).toString('base64'),
-    },
-  };
-  try {
-    await getSample().program.translateText(event);
-  } catch (err) {
-    assert.deepStrictEqual(err, error);
-  }
-});
-
-it('translateText fails without a filename', async () => {
-  const error = new Error(
-    'Filename not provided. Make sure you have a "filename" property in your request'
-  );
-  const event = {
-    data: {
-      data: Buffer.from(JSON.stringify({text})).toString('base64'),
-    },
-  };
-
-  try {
-    await getSample().program.translateText(event);
-  } catch (err) {
-    assert.deepStrictEqual(err, error);
-  }
-});
-
-it('translateText fails without a lang', async () => {
-  const error = new Error(
-    'Language not provided. Make sure you have a "lang" property in your request'
-  );
-  const event = {
-    data: {
-      data: Buffer.from(JSON.stringify({text, filename})).toString('base64'),
-    },
-  };
-
-  try {
-    await getSample().program.translateText(event);
-  } catch (err) {
-    assert.deepStrictEqual(err, error);
-  }
-});
-
-it('translateText translates and publishes text with Node 6 arguments', async () => {
-  const event = {
-    data: {
+    };
+    try {
+      await program.translateText(event);
+      assert.fail('no error thrown');
+    } catch (err) {
+      assert.deepStrictEqual(err.message, errorMsg('Text'));
+    }
+  });
+
+  it('translateText translates and publishes text', async () => {
+    const data = {
       data: Buffer.from(
         JSON.stringify({
           text,
@@ -248,154 +88,54 @@ it('translateText translates and publishes text with Node 6 arguments', async ()
           lang,
         })
       ).toString('base64'),
-    },
-  };
-  const sample = getSample();
-
-  sample.mocks.translate.translate.returns(Promise.resolve([translation]));
+    };
 
-  await sample.program.translateText(event);
-  assert.strictEqual(console.log.callCount, 2);
-  assert.deepStrictEqual(console.log.firstCall.args, [
-    `Translating text into ${lang}`,
-  ]);
-  assert.deepStrictEqual(console.log.secondCall.args, [
-    `Text translated to ${lang}`,
-  ]);
+    await program.translateText(data);
+    assert.ok(console.log.calledWith(`Translating text into ${lang}`));
+    assert.ok(console.log.calledWith(`Text translated to ${lang}`));
+  });
 });
 
-it('translateText translates and publishes text with Node 8 arguments', async () => {
-  const data = {
-    data: Buffer.from(
-      JSON.stringify({
-        text,
-        filename,
-        lang,
-      })
-    ).toString('base64'),
-  };
-  const sample = getSample();
-
-  sample.mocks.translate.translate.returns(Promise.resolve([translation]));
-
-  await sample.program.translateText(data);
-  assert.strictEqual(console.log.callCount, 2);
-  assert.deepStrictEqual(console.log.firstCall.args, [
-    `Translating text into ${lang}`,
-  ]);
-  assert.deepStrictEqual(console.log.secondCall.args, [
-    `Text translated to ${lang}`,
-  ]);
-});
-
-it('saveResult fails without text', async () => {
-  const error = new Error(
-    'Text not provided. Make sure you have a "text" property in your request'
-  );
-  const event = {
-    data: {
-      data: Buffer.from(JSON.stringify({})).toString('base64'),
-    },
-  };
-
-  try {
-    await getSample().program.saveResult(event);
-  } catch (err) {
-    assert.deepStrictEqual(err, error);
-  }
-});
-
-it('saveResult fails without a filename', async () => {
-  const error = new Error(
-    'Filename not provided. Make sure you have a "filename" property in your request'
-  );
-  const event = {
-    data: {
-      data: Buffer.from(JSON.stringify({text})).toString('base64'),
-    },
-  };
-
-  try {
-    await getSample().program.saveResult(event);
-  } catch (err) {
-    assert.deepStrictEqual(err, error);
-  }
-});
-
-it('saveResult fails without a lang', async () => {
-  const error = new Error(
-    'Language not provided. Make sure you have a "lang" property in your request'
-  );
-  const event = {
-    data: {
+describe('saveResult', () => {
+  it('saveResult validates parameters', async () => {
+    const event = {
       data: Buffer.from(JSON.stringify({text, filename})).toString('base64'),
-    },
-  };
-
-  try {
-    await getSample().program.saveResult(event);
-  } catch (err) {
-    assert.deepStrictEqual(err, error);
-  }
-});
-
-it('saveResult translates and publishes text with Node 6 arguments', async () => {
-  const event = {
-    data: {
+    };
+
+    try {
+      await program.saveResult(event);
+      assert.fail('no error thrown');
+    } catch (err) {
+      assert.deepStrictEqual(err.message, errorMsg('Language', 'lang'));
+    }
+  });
+
+  it('saveResult translates and publishes text', async () => {
+    const data = {
       data: Buffer.from(JSON.stringify({text, filename, lang})).toString(
         'base64'
       ),
-    },
-  };
-  const sample = getSample();
-
-  await sample.program.saveResult(event);
-  assert.strictEqual(console.log.callCount, 3);
-  assert.deepStrictEqual(console.log.getCall(0).args, [
-    `Received request to save file ${filename}`,
-  ]);
-  assert.deepStrictEqual(console.log.getCall(1).args, [
-    `Saving result to ${filename}_to_${lang}.txt in bucket ${sample.mocks.config.RESULT_BUCKET}`,
-  ]);
-  assert.deepStrictEqual(console.log.getCall(2).args, ['File saved.']);
-});
-
-it('saveResult translates and publishes text with Node 8 arguments', async () => {
-  const data = {
-    data: Buffer.from(JSON.stringify({text, filename, lang})).toString(
-      'base64'
-    ),
-  };
-  const sample = getSample();
-
-  await sample.program.saveResult(data);
-  assert.strictEqual(console.log.callCount, 3);
-  assert.deepStrictEqual(console.log.getCall(0).args, [
-    `Received request to save file ${filename}`,
-  ]);
-  assert.deepStrictEqual(console.log.getCall(1).args, [
-    `Saving result to ${filename}_to_${lang}.txt in bucket ${sample.mocks.config.RESULT_BUCKET}`,
-  ]);
-  assert.deepStrictEqual(console.log.getCall(2).args, ['File saved.']);
-});
+    };
 
-it('saveResult translates and publishes text with dot in filename', async () => {
-  const event = {
-    data: {
-      data: Buffer.from(
-        JSON.stringify({text, filename: `${filename}.jpg`, lang})
-      ).toString('base64'),
-    },
-  };
-  const sample = getSample();
+    const newFilename = `${filename}_to_${lang}.txt`;
 
-  await sample.program.saveResult(event);
-  assert.strictEqual(console.log.callCount, 3);
-  assert.deepStrictEqual(console.log.getCall(0).args, [
-    `Received request to save file ${filename}.jpg`,
-  ]);
-  assert.deepStrictEqual(console.log.getCall(1).args, [
-    `Saving result to ${filename}.jpg_to_${lang}.txt in bucket ${sample.mocks.config.RESULT_BUCKET}`,
-  ]);
-  assert.deepStrictEqual(console.log.getCall(2).args, ['File saved.']);
+    await program.saveResult(data);
+    assert.ok(
+      console.log.calledWith(`Received request to save file ${filename}`)
+    );
+    assert.ok(
+      console.log.calledWith(
+        `Saving result to ${newFilename} in bucket ${RESULT_BUCKET}`
+      )
+    );
+    assert.ok(console.log.calledWith('File saved.'));
+
+    // Check file was actually saved
+    assert.ok(
+      storage
+        .bucket(RESULT_BUCKET)
+        .file(newFilename)
+        .exists()
+    );
+  });
 });