【问题标题】:Date Unit test passed locally but failed in Gitlab CD/CI pipeline日期 单元测试在本地通过但在 Gitlab CD/CI 管道中失败
【发布时间】:2022-02-13 16:23:53
【问题描述】:

对于日期验证,我为我的应用使用了luxon。对于每个功能,我都进行了单元测试。我的单元测试在本地通过,但是当我在 gitlab 中部署我的代码时,我的大部分测试都失败了。预期的结果与收到的结果大不相同。我不明白出了什么问题。这是我的 CD/CI 管道映像。 Image-1image-2Image-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)
  })
})

【问题讨论】:

  • 变化的可能来源是系统的时区。它可能适用于您当地的时区,但不适用于 UTC 或您的跑步者的时区。声明时区的日期时间输入可能由库转换为本地时间。因此,当本地时区与您的不同时,值的差异。您会注意到几个示例正好相差两个小时(预期:00:00 实际:22:00)——如果您在 UTC+2 时区,这将证实怀疑。

标签: unit-testing date gitlab gitlab-ci luxon


【解决方案1】:

差异与您本地计算机的时区和 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:(强调添加)

日期时间包括:

[...]
一个时区。每个实例都在特定区域的上下文中被考虑(默认情况下是本地系统的区域)。
[...]

您可能希望标准化您的测试以使用特定时区。有关如何更改 datetime 对象的时区的提示,请参阅 this question

【讨论】:

  • 非常感谢您的精彩解释。
猜你喜欢
  • 2021-03-20
  • 2022-01-17
  • 2022-01-26
  • 1970-01-01
  • 2017-05-07
  • 1970-01-01
  • 2021-11-30
  • 2019-12-07
  • 1970-01-01
相关资源
最近更新 更多