• Typescript migration headaches

    June 11, 2018 - 2 minute read -
    node-js typescript javaScript

    I had the pleasure of migrating an existing codebase from straight nodejs to Typescript. Here’s a few of the headaches/gotchas I ran into.

    Extending from Error breaks things

    The following custom error class resulted in an error complaining about instanceof:

    class ApiError extends Error {
        constructor(message: string) {
          this.name = 'ApiError';
        }
    }

    Microsoft explain the issue and point out a simple fix in their Breaking Changes list

    Mocha not picking up sub directories with –recursive

    With a test structure like:

    test/controllers/book.spec.ts
    test/middleware/log.spec.ts
    test/app.spec.ts

    running mocha --recursive test/**/*.spec.ts will only see mocha pickup tests in app.spec.ts, despite the --recursive option being set.

    As ScottFreeCode points out the solution is to quote the glob to avoid having the shell interpret the **.

    Eg. mocha --recursive "test/**/*.spec.ts"

    Typescript compiler will not touch non-ts/js files

    There’s no built in mechanism to have the compiler copy non-typescript/javascript files, such as .json schemas to the dist directory. This instead needs to be done separately.

    With only a few files to copy I ended up creating a simple bin script to copy the files before running tsc.

    Sequelize unexpected token in map file error

    A fairly common pattern to follow when using Sequelize is to load all model files defined in a particular directory, with code like:

    fs.readdirSync('models/').forEach((filename) => {
      ... load model
    	models[model] = model;
    });

    This works fine with javascript, but will cause a runtime Unexpected token with Typescript when map file generation is turned on. Any code loading files should be modified to explicitly check the extension. In this case, we want to exclude any *.map.js files from being loaded.

    More details can be found on this TypeScript github issue.

    Cannot redeclare block-scoped variable

    With a codebase split up amongst a number of files, Typescript instantly complained about Cannot redeclare block-scoped variable whenever attempting to load a local file.

    The solution is to ensure each file exported every function/variable used in other files.

    export function doSomething() {
      ...
    }
    
    export function doSomethingElse() {
      ...
    }
    module.exports = { doSomething, doSomethingElse};
  • Run Rails tests on Gitlab CI with a Postgres database

    December 13, 2016 - 1 minute read -
    rails rake-test gitlab-ci postgres

    Gitlab CI can be used to run rails tests on every push. It’s pretty straight forward to setup.

    First create a .gitlab-ci.yml file:

    image: ruby:2.3
    
    services:
      - postgres:latest
    
    variables:
      POSTGRES_DB: dbname # set database
      POSTGRES_USER: username # set username
      POSTGRES_PASSWORD: ""
    
    before_script:
      - apt-get update -qy
      - apt-get install -y nodejs
      - bundle install --path /cache
    
    # run tests
    test:
      script:
        - cp config/database-gitlab.yml config/database.yml
        - bundle exec rake db:create RAILS_ENV=test
        - bundle exec rake test

    The before_script installs everything we need to run the tests. test job creates the database and executes the tests.

    Next, create a gitlab specific database config config/database-gitlab.yml to connect to the database setup earlier.

    test: adapter: postgresql
    pool: 5
    timeout: 5000
    host: postgres
    database: dbname # set database
    user: username # set username

    Now the tests will be run on each push!

  • Reading passwords from a file with Selenium IDE and SelBlock

    April 14, 2016 - 1 minute read -
    selenium-ide selenium selblocks

    Recently I found the need to have Selenium loop through a bunch of commands for different users, each with their own usernames and passwords.

    Thankfully, it's fairly painless to setup using the SelBlock plugin for Selenium IDE.

    Create a datafile:

    [{ user: "ash", pass: "test1234" }
    ,{ user: "brock", pass: "test1234" }
    ,{ user: "jessie", pass: "test1234" }
    ,{ user: "james", pass: "test1234" }
    ,{ user: "misty", pass: "test1234" }]

    If the file is saved in the same directory as the test script, you can use a relative path.

    Loop through it and log the username:

    forJson varset.json
      getEval LOG.info("user is "${user}")
    endForJson
  • Older posts