text: 'use strict';
  
  const redis = require('ioredis');
  
  const utils = require('./utils');
  const expect = require('chai').expect;
  
  const _ = require('lodash');
  
  describe('Jobs getters', function() {
    this.timeout(12000);
    let queue;
    let client;
  
    beforeEach(() => {
      client = new redis();
      return client.flushdb();
    });
  
    beforeEach(() => {
      queue = utils.buildQueue();
    });
  
    afterEach(function() {
      this.timeout(
        queue.settings.stalledInterval * (1 + queue.settings.maxStalledCount)
      );
      return queue
        .clean(1000)
        .then(() => {
          return queue.close();
        })
        .then(() => {
          return client.quit();
        });
    });
  
    it('should get waiting jobs', () => {
      return Promise.all([
        queue.add({ foo: 'bar' }),
        queue.add({ baz: 'qux' })
      ]).then(() => {
        return queue.getWaiting().then(jobs => {
          expect(jobs).to.be.a('array');
          expect(jobs.length).to.be.equal(2);
          expect(jobs[0].data.foo).to.be.equal('bar');
          expect(jobs[1].data.baz).to.be.equal('qux');
        });
      });
    });
  
    it('should get paused jobs', () => {
      return queue.pause().then(() => {
        return Promise.all([
          queue.add({ foo: 'bar' }),
          queue.add({ baz: 'qux' })
        ]).then(() => {
          return queue.getWaiting().then(jobs => {
            expect(jobs).to.be.a('array');
            expect(jobs.length).to.be.equal(2);
            expect(jobs[0].data.foo).to.be.equal('bar');
            expect(jobs[1].data.baz).to.be.equal('qux');
          });
        });
      });
    });
  
    it('should get active jobs', done => {
      queue.process((job, jobDone) => {
        queue.getActive().then(jobs => {
          expect(jobs).to.be.a('array');
          expect(jobs.length).to.be.equal(1);
          expect(jobs[0].data.foo).to.be.equal('bar');
          done();
        });
        jobDone();
      });
  
      queue.add({ foo: 'bar' });
    });
  
    it('should get a specific job', done => {
      const data = { foo: 'sup!' };
      queue.add(data).then(job => {
        queue.getJob(job.id).then(returnedJob => {
          expect(returnedJob.data).to.eql(data);
          expect(returnedJob.id).to.be.eql(job.id);
          done();
        });
      });
    });
  
    it('should get completed jobs', done => {
      let counter = 2;
  
      queue.process((job, jobDone) => {
        jobDone();
      });
  
      queue.on('completed', () => {
        counter--;
  
        if (counter === 0) {
          queue.getCompleted().then(jobs => {
            expect(jobs).to.be.a('array');
            // We need a "empty completed" kind of function.
            //expect(jobs.length).to.be.equal(2);
            done();
          });
        }
      });
  
      queue.add({ foo: 'bar' });
      queue.add({ baz: 'qux' });
    });
  
    it('should get completed jobs excluding their data', done => {
      let counter = 2;
  
      queue.process((job, jobDone) => {
        jobDone();
      });
  
      queue.on('completed', () => {
        counter--;
  
        if (counter === 0) {
          queue.getCompleted(0, -1, { excludeData: true }).then(jobs => {
            expect(jobs).to.be.a('array');
            expect(jobs).to.have.length(2);
            expect(jobs[0]).to.have.property('data');
            expect(jobs[0].data).to.be.empty;
            expect(jobs[1]).to.have.property('data');
            expect(jobs[1].data).to.be.empty;
            done();
          });
        }
      });
  
      queue.add({ foo: 'bar' });
      queue.add({ baz: 'qux' });
    });
  
    it('should get failed jobs', done => {
      let counter = 2;
  
      queue.process((job, jobDone) => {
        jobDone(new Error('Forced error'));
      });
  
      queue.on('failed', () => {
        counter--;
  
        if (counter === 0) {
          queue.getFailed().then(jobs => {
            expect(jobs).to.be.a('array');
            done();
          });
        }
      });
  
      queue.add({ foo: 'bar' });
      queue.add({ baz: 'qux' });
    });
  
    it('fails jobs that exceed their specified timeout', done => {
      queue.process((job, jobDone) => {
        setTimeout(jobDone, 200);
      });
  
      queue.on('failed', (job, error) => {
        expect(error.message).to.contain('timed out');
        done();
      });
  
      queue.on('completed', () => {
        const error = new Error('The job should have timed out');
        done(error);
      });
  
      queue.add(
        { some: 'data' },
        {
          timeout: 100
        }
      );
    });
  
    it('should return all completed jobs when not setting start/end', done => {
      queue.process((job, completed) => {
        completed();
      });
  
      queue.on(
        'completed',
        _.after(3, () => {
          queue
            .getJobs('completed')
            .then(jobs => {
              expect(jobs)
                .to.be.an('array')
                .that.have.length(3);
              expect(jobs[0]).to.have.property('finishedOn');
              expect(jobs[1]).to.have.property('finishedOn');
              expect(jobs[2]).to.have.property('finishedOn');
  
              expect(jobs[0]).to.have.property('processedOn');
              expect(jobs[1]).to.have.property('processedOn');
              expect(jobs[2]).to.have.property('processedOn');
              done();
            })
            .catch(done);
        })
      );
  
      queue.add({ foo: 1 });
      queue.add({ foo: 2 });
      queue.add({ foo: 3 });
    });
  
    it('should return all failed jobs when not setting start/end', done => {
      queue.process((job, completed) => {
        completed(new Error('error'));
      });
  
      queue.on(
        'failed',
        _.after(3, () => {
          queue
            .getJobs('failed')
            .then(jobs => {
              expect(jobs)
                .to.be.an('array')
                .that.has.length(3);
              expect(jobs[0]).to.have.property('finishedOn');
              expect(jobs[1]).to.have.property('finishedOn');
              expect(jobs[2]).to.have.property('finishedOn');
  
              expect(jobs[0]).to.have.property('processedOn');
              expect(jobs[1]).to.have.property('processedOn');
              expect(jobs[2]).to.have.property('processedOn');
              done();
            })
            .catch(done);
        })
      );
  
      queue.add({ foo: 1 });
      queue.add({ foo: 2 });
      queue.add({ foo: 3 });
    });
  
    it('should return subset of jobs when setting positive range', done => {
      queue.process((job, completed) => {
        completed();
      });
  
      queue.on(
        'completed',
        _.after(3, () => {
          queue
            .getJobs('completed', 1, 2, true)
            .then(jobs => {
              expect(jobs)
                .to.be.an('array')
                .that.has.length(2);
              expect(jobs[0].data.foo).to.be.eql(2);
              expect(jobs[1].data.foo).to.be.eql(3);
              expect(jobs[0]).to.have.property('finishedOn');
              expect(jobs[1]).to.have.property('finishedOn');
              expect(jobs[0]).to.have.property('processedOn');
              expect(jobs[1]).to.have.property('processedOn');
              done();
            })
            .catch(done);
        })
      );
  
      queue
        .add({ foo: 1 })
        .then(() => {
          return queue.add({ foo: 2 });
        })
        .then(() => {
          return queue.add({ foo: 3 });
        });
    });
  
    it('should return subset of jobs when setting a negative range', done => {
      queue.process((job, completed) => {
        completed();
      });
  
      queue.on(
        'completed',
        _.after(3, () => {
          queue
            .getJobs('completed', -3, -1, true)
            .then(jobs => {
              expect(jobs)
                .to.be.an('array')
                .that.has.length(3);
              expect(jobs[0].data.foo).to.be.equal(1);
              expect(jobs[1].data.foo).to.be.eql(2);
              expect(jobs[2].data.foo).to.be.eql(3);
              done();
            })
            .catch(done);
        })
      );
  
      queue.add({ foo: 1 });
      queue.add({ foo: 2 });
      queue.add({ foo: 3 });
    });
  
    it('should return subset of jobs when range overflows', done => {
      queue.process((job, completed) => {
        completed();
      });
  
      queue.on(
        'completed',
        _.after(3, () => {
          queue
            .getJobs('completed', -300, 99999, true)
            .then(jobs => {
              expect(jobs)
                .to.be.an('array')
                .that.has.length(3);
              expect(jobs[0].data.foo).to.be.equal(1);
              expect(jobs[1].data.foo).to.be.eql(2);
              expect(jobs[2].data.foo).to.be.eql(3);
              done();
            })
            .catch(done);
        })
      );
  
      queue.add({ foo: 1 });
      queue.add({ foo: 2 });
      queue.add({ foo: 3 });
    });
  
    it('should return jobs for multiple types', done => {
      let counter = 0;
      queue.process((/*job*/) => {
        counter++;
        if (counter == 2) {
          return queue.pause();
        }
      });
  
      queue.on(
        'completed',
        _.after(2, () => {
          queue
            .getJobs(['completed', 'paused'])
            .then(jobs => {
              expect(jobs).to.be.an('array');
              expect(jobs).to.have.length(3);
              done();
            })
            .catch(done);
        })
      );
  
      queue.add({ foo: 1 });
      queue.add({ foo: 2 });
      queue.add({ foo: 3 });
    });
  });
  