如何将含日期计算的字符串解析为日期对象?Cucumber测试技术问询
First off, your current implementation is a solid start—let’s build on it to support all time units (minutes, hours, months, etc.) without reinventing the wheel. The key here is leaning into a battle-tested date library that natively handles relative time calculations, which will save you from writing custom regex logic for every possible unit.
Step 1: Use a Robust Date Library (Moment.js or Day.js)
Both libraries support all common time units (minutes, hours, days, months, etc.) out of the box. If you’re looking for something lighter, Day.js is a great drop-in replacement for Moment.js. For this example, we’ll stick with Moment.js since you’re already familiar with its API.
Step 2: Update Your String Replacement Logic
Modify your regex to capture the optional time unit (defaulting to days for backward compatibility) and adjust the replacement function to use that unit dynamically:
function stringReplaceNow(string) { // Updated regex to capture format, offset sign/amount, and optional time unit var regex = /<now:([A-Z0-9-]+):?((\+|-)([0-9]+)):?([a-z]+)?>/gi; return string.replace(regex, function (match, format, shouldModify, modification, modAmount, unit) { // Fallback to 'days' if no unit is specified (keeps old syntax working) const timeUnit = unit || 'days'; let date = moment(); if (modification === '+') { date = date.add(modAmount, timeUnit); } else if (modification === '-') { date = date.subtract(modAmount, timeUnit); } return date.format(format); }); }
Updated Cucumber Table Example
Now you can use any supported time unit in your feature files:
| Name | Datetime | State |
|---|---|---|
| Johnson | <now:DD-MM-YYYY:-2> | Processing |
| Minter | <now:HH:mm:ss:+15:minutes> | Processing |
| Brown | <now:YYYY-MM-DD:+1:months> | Done |
Step 3: Handle WireMock’s {{now offset='+15 minutes'}} Format
To validate dates returned by WireMock, you’ll need to parse its offset syntax and compute the expected datetime. Here’s a helper function to do that:
function parseWireMockNowOffset(offsetStr) { // Match patterns like "+15 minutes", "-3 days" const offsetRegex = /([+-])(\d+) (\w+)/; const matches = offsetStr.match(offsetRegex); if (!matches) throw new Error(`Invalid offset format: ${offsetStr}`); const [, sign, amount, unit] = matches; let date = moment(); if (sign === '+') { date = date.add(parseInt(amount), unit); } else { date = date.subtract(parseInt(amount), unit); } return date; } // Usage example: Calculate expected datetime from WireMock's offset const wireMockOffset = "+15 minutes"; const expectedDatetime = parseWireMockNowOffset(wireMockOffset).format("YYYY-MM-DDTHH:mm:ss");
Step 4: Validate Datetime Accuracy and Sorting
Accuracy Check
When verifying WireMock’s response, compare the returned datetime to your computed expected value. Allow a small tolerance (e.g., 1 second) to account for test execution delay:
const actualDatetime = moment(response.body.datetime); const expectedDatetime = parseWireMockNowOffset("+15 minutes"); // Ensure actual time is within 1 second of the expected value expect(actualDatetime.diff(expectedDatetime, 'seconds')).toBeLessThanOrEqual(1);
Sorting Validation
To confirm your table is sorted correctly, convert all datetimes to timestamps and check the order:
// Extract items from the response and sort them by datetime const sortedItems = [...response.body.items].sort((a, b) => moment(a.datetime).valueOf() - moment(b.datetime).valueOf() ); // Verify the original response matches the sorted order expect(response.body.items).toEqual(sortedItems);
Alternative: Use Native Date APIs (If You Avoid Libraries)
If you don’t want to add a dependency, you can use JavaScript’s native Date object with helper functions for relative time. Note that this requires more code to handle edge cases like month rollovers:
function addRelativeTime(date, amount, unit) { const newDate = new Date(date); switch(unit) { case 'minutes': newDate.setMinutes(newDate.getMinutes() + amount); break; case 'hours': newDate.setHours(newDate.getHours() + amount); break; case 'days': newDate.setDate(newDate.getDate() + amount); break; case 'months': newDate.setMonth(newDate.getMonth() + amount); break; default: throw new Error(`Unsupported unit: ${unit}`); } return newDate; }
Libraries like Moment/Day.js handle these edge cases automatically, which is a big win for test reliability.
内容的提问来源于stack exchange,提问作者Appernicus

