日期单元测试在本地通过但在 Gitlab CD/CI 管道中失败

Date Unit test passed locally but failed in Gitlab CD/CI pipeline

对于日期验证,我使用了 luxon for my app. For each function I have made unit test. My unit test passed locally but when I deployed my code in gitlab, Most of my test failed. The expected result is so different than received. I don't understand what's the wrong. This my CD/CI pipeline images. Image-1, image-2, Image-3 而且还有更多。 基本上我的测试都失败了

我的所有测试都通过了code-sandbox

这些是我的所有功能:

import {
  DateTime
} from 'luxon'

export const DEFAULT_DATE_FORMAT = 'd.M.yyyy'
export const SHORT_TIME_FORMAT = 'HH:mm'
export const ISO_DATE_FORMAT = 'yyyy-MM-dd'
export const DATE_TIME_FORMAT = 'd.M.yyyy HH:mm'
export const DATE_MONTH_FORMAT = 'd.M'

export const WEEKDAYS = [
  'SUNDAY',
  'MONDAY',
  'TUESDAY',
  'WEDNESDAY',
  'THURSDAY',
  'FRIDAY',
  'SATURDAY',
]

export const dateToStrings = (date: string | number | Date): DateTime =>
  DateTime.fromISO(new Date(date).toISOString())

export const formatDateTime = (date: string | number | Date): string =>
  dateToStrings(date).toFormat(DATE_TIME_FORMAT)
export const formatDateMonthYear = (date: string | number | Date): string =>
  dateToStrings(date).toFormat(DEFAULT_DATE_FORMAT)

export const formatTime = (date: string | number | Date): string =>
  dateToStrings(date).toFormat(SHORT_TIME_FORMAT)

export const NextDayFormatYearMonthDate = (date: string | number | Date): string =>
  dateToStrings(date).plus({
    days: 1
  }).toFormat(ISO_DATE_FORMAT)

export const PreviousDayFormatYearMonthDate = (date: string | number | Date): string =>
  dateToStrings(date).plus({
    days: -1
  }).toFormat(ISO_DATE_FORMAT)

export const dateDifference = (date: string | number | Date): number => {
  const diff = dateToStrings(date).diff(DateTime.now(), 'days').toObject()

  return Math.abs(Math.ceil(diff.days as number))
}

export const formatYearMonthDate = (date: Date | string | undefined): string => {
  if (!date) {
    //  if date is undefined, return empty string
    return ''
  } else {
    return dateToStrings(date).toFormat(ISO_DATE_FORMAT)
  }
}
export const weekNumber = (date: string | Date): number =>
  dateToStrings(date).startOf('week').weekNumber

export const nextWeek = (date: string | Date): string =>
  dateToStrings(date).startOf('week').plus({
    days: 7
  }).toFormat(ISO_DATE_FORMAT)

export const previousWeek = (date: string | Date): string =>
  dateToStrings(date).startOf('week').plus({
    days: -7
  }).toFormat(ISO_DATE_FORMAT)
export const firstDateOfWeek = (date: string | Date): string =>
  dateToStrings(date).startOf('week').toFormat(ISO_DATE_FORMAT)

export const lastDateOfWeek = (date: string | Date): string =>
  dateToStrings(date).startOf('week').plus({
    days: 6
  }).toFormat(ISO_DATE_FORMAT)

export const firstMondayOfTheWeekWithGMT = (date: Date): Date =>
  dateToStrings(date).startOf('week').toJSDate()

export const formatDateMonth = (date: string | Date): string =>
  dateToStrings(date).toFormat(DATE_MONTH_FORMAT)

export const shortDateString = (date: Date): string => {
  const shortForm = dateToStrings(date).setLocale('fi').toFormat('EEE')
  return shortForm.length > 1 ? `${shortForm.charAt(0).toUpperCase()}${shortForm.slice(1)}` : ''
}

export const hasSameDay = (date1: Date, date2: Date): boolean =>
  dateToStrings(date1).hasSame(dateToStrings(date2), 'day')

export const isToday = (date: string | number | Date): boolean => {
  return dateToStrings(date).toISODate() === DateTime.local().toISODate()
}

export const compareDays = (
  date1: Date | string | number,
  date2: Date | string | number,
): number => {
  const compareWithDay = dateToStrings(date1).diff(dateToStrings(date2), ['days']).toObject()

  return Math.abs(Math.ceil(compareWithDay.days as number))
}

这是我所有的测试

import {
  formatDateTime,
  formatDateMonthYear,
  formatTime,
  NextDayFormatYearMonthDate,
  PreviousDayFormatYearMonthDate,
  dateDifference,
  formatYearMonthDate,
  weekNumber,
  nextWeek,
  previousWeek,
  firstDateOfWeek,
  lastDateOfWeek,
  formatDateMonth,
  shortDateString,
  compareDays,
  DATE_MONTH_FORMAT,
  DEFAULT_DATE_FORMAT,
  SHORT_TIME_FORMAT,
  ISO_DATE_FORMAT,
  DATE_TIME_FORMAT,
} from 'utils/date'
import { DateTime } from 'luxon'

const toDateString = 'Mon Feb 07 2022 00:00:00 GMT+0200 (Eastern European Standard Time)'
const toISOString = '2018-05-01T13:44:48.708709Z'
const today = new Date()
const tomorrow = new Date(today.getTime() + 24 * 60 * 60 * 1000)
const yesterday = new Date(today.getTime() - 24 * 60 * 60 * 1000)

describe('formatDateTime', () => {
  it('Should return format date time when date is string', () => {
    expect(formatDateTime('2022-02-11T06:44:57+00:00')).toBe('7.2.2022 00:00')
  })

  it('Should return format date time when date is toISOString', () => {
    expect(formatDateTime(toISOString)).toBe('1.5.2018 16:44')
  })
  it('Should return format date time when date is today', () => {
    expect(formatDateTime(today)).toBe(
      DateTime.fromISO(new Date().toISOString()).toFormat(DATE_TIME_FORMAT),
    )
  })
})

describe('formatDateMonthYear', () => {
  it('Should return format date when date is string', () => {
    expect(formatDateMonthYear(toDateString)).toBe('7.2.2022')
  })

  it('Should return format date when date is ISO String', () => {
    expect(formatDateMonthYear(toISOString)).toBe('1.5.2018')
  })

  it('Should return format date when date is today', () => {
    expect(formatDateMonthYear(today)).toBe(
      DateTime.fromISO(new Date().toISOString()).toFormat(DEFAULT_DATE_FORMAT),
    )
  })
})

describe('formatTime', () => {
  it('Should return 00:00 when there is no time', () => {
    expect(formatTime(toDateString)).toBe('00:00')
  })

  it('Should return format time', () => {
    expect(formatTime(toISOString)).toBe('16:44')
  })

  it('Should return format time when date is today', () => {
    expect(formatTime(today)).toBe(
      DateTime.fromISO(new Date().toISOString()).toFormat(SHORT_TIME_FORMAT),
    )
  })
})

describe('NextDayFormatYearMonthDate ', () => {
  it('Should return next day format year when date is string', () => {
    expect(NextDayFormatYearMonthDate(toDateString)).toBe('2022-02-08')
  })

  it('Should return next day format year when date is ISOString', () => {
    expect(NextDayFormatYearMonthDate(toISOString)).toBe('2018-05-02')
  })
  it('Should return next day format year when date is today', () => {
    expect(NextDayFormatYearMonthDate(today)).toBe(
      DateTime.fromISO(new Date().toISOString()).plus({ days: 1 }).toFormat(ISO_DATE_FORMAT),
    )
  })
})

describe('PreviousDayFormatYearMonthDate', () => {
  it('Should return next day format year when date is string', () => {
    expect(PreviousDayFormatYearMonthDate(toDateString)).toBe('2022-02-06')
  })

  it('Should return next day format year when date is ISOString', () => {
    expect(PreviousDayFormatYearMonthDate(toISOString)).toBe('2018-04-30')
  })
  it('Should return next day format year when date is today', () => {
    expect(PreviousDayFormatYearMonthDate(today)).toBe(
      DateTime.fromISO(new Date().toISOString()).plus({ days: -1 }).toFormat(ISO_DATE_FORMAT),
    )
  })
})

describe('dateDifference', () => {
  it('Should return 0 when date is today', () => {
    expect(dateDifference(today)).toBe(0)
  })

  it('Should return 1 when date is not today', () => {
    expect(dateDifference(tomorrow)).toBe(1)
  })

  it('Should return 1 when date is not today', () => {
    expect(dateDifference(yesterday)).toBe(1)
  })
})

describe('formatYearMonthDate', () => {
  it('Should return format date when date is string', () => {
    expect(formatYearMonthDate(toDateString)).toBe('2022-02-07')
  })

  it('Should return format date when date is ISO String', () => {
    expect(formatYearMonthDate(toISOString)).toBe('2018-05-01')
  })

  it('Should return format date when date is today', () => {
    expect(formatYearMonthDate(today)).toBe(
      DateTime.fromISO(new Date().toISOString()).toFormat(ISO_DATE_FORMAT),
    )
  })

  it('Should return empty string when date is undefined', () => {
    expect(formatYearMonthDate(undefined)).toBe('')
  })
})

describe('weekNumber', () => {
  it('Should return week number when date is string', () => {
    expect(weekNumber(toDateString)).toBe(6)
  })

  it('Should return week number when date is ISO String', () => {
    expect(weekNumber(toISOString)).toBe(18)
  })

  it('Should return week number when date is today', () => {
    expect(weekNumber(today)).toBe(DateTime.fromISO(new Date().toISOString()).weekNumber)
  })
})

describe('nextWeek', () => {
  it('Should return next week date when date is string', () => {
    expect(nextWeek(toDateString)).toBe('2022-02-14')
  })

  it('Should return next week date when date is ISO String', () => {
    expect(nextWeek(toISOString)).toBe('2018-05-07')
  })
})

describe('previousWeek', () => {
  it('Should return previous week date when date is string', () => {
    expect(previousWeek(toDateString)).toBe('2022-01-31')
  })

  it('Should return previous week date when date is ISO String', () => {
    expect(previousWeek(toISOString)).toBe('2018-04-23')
  })
})

describe('firstDateOfWeek', () => {
  it('Should return first date of the week when date is string', () => {
    expect(firstDateOfWeek(toDateString)).toBe('2022-02-07')
  })

  it('Should return first date of the week when date is ISO String', () => {
    expect(firstDateOfWeek(toISOString)).toBe('2018-04-30')
  })
})

describe('lastDateOfWeek', () => {
  it('Should return first date of the week when date is string', () => {
    expect(lastDateOfWeek(toDateString)).toBe('2022-02-13')
  })

  it('Should return first date of the week when date is ISO String', () => {
    expect(lastDateOfWeek(toISOString)).toBe('2018-05-06')
  })
})

describe('formatDateMonth', () => {
  it('Should return format date month when date is string', () => {
    expect(formatDateMonth(toDateString)).toBe('7.2')
  })

  it('Should return format date month when date is ISO String', () => {
    expect(formatDateMonth(toISOString)).toBe('1.5')
  })

  it('Should return format date month when date is today', () => {
    expect(formatDateMonth(today)).toBe(
      DateTime.fromISO(new Date().toISOString()).toFormat(DATE_MONTH_FORMAT),
    )
  })
})

describe('shortDateString', () => {
  it('Should return first two letters Finnish weekdays when date is string', () => {
    expect(shortDateString(new Date(toDateString))).toBe('Ma')
  })

  it('Should return first two letters Finnish weekdays when date is ISO String', () => {
    expect(shortDateString(new Date(toISOString))).toBe('Ti')
  })
})

describe('compareDays', () => {
  it('Should return 0 if the dates are same', () => {
    expect(compareDays(new Date(toDateString), new Date(toDateString))).toBe(0)
  })

  it('Should return 0 if the dates are same', () => {
    expect(compareDays(new Date(toDateString), new Date(toISOString))).toBe(1378)
  })

  it('Should return 0 if the dates are string', () => {
    expect(compareDays(toDateString, toISOString)).toBe(1378)
  })
})

区别与您本地计算机的时区和 GitLab 运行器的时区有关。 GitLab 运行器使用 UTC 时区。

以这个案例为例:

const toDateString = 'Mon Feb 07 2022 00:00:00 GMT+0200 (Eastern European Standard Time)'
// ...
describe('formatTime', () => {
  it('Should return 00:00 when there is no time', () => {
    expect(formatTime(toDateString)).toBe('00:00')
  })

在你的单元测试结果中:

Expected: "00:00"
Received: "22:00"

如果您的本地时区是 UTC+2,这将通过,但如果您的时区是 UTC,则会失败。 Mon Feb 07 2022 00:00:00 GMT+0200 在 UTC 时间是 Sun Feb 06 2022 22:00:00

来自luxon docs:(强调)

A DateTime comprises of:

[...]
A time zone. Each instance is considered in the context of a specific zone (by default the local system's zone).
[...]

您可能希望规范化您的测试以使用特定时区。有关如何更改日期时间对象的时区的提示,请参阅