         }
     }
     
+    /// Assert that for every task id all operations (task start, task end and non task) are performed
     private func XCTAssertAllOperationsPerformed(_ taskIds: [String], file: StaticString = #file, line: UInt = #line) async {
         let count = await timeline.numberOfOperations
         XCTAssertEqual(count, taskIds.count * Operation.Kind.allCases.count, file: file, line: line)
     }
     
-    private func XCTAssertTaskOrderEqual(_ taskIds: [String], expectedOrder: [Operation.Kind], file: StaticString = #file, line: UInt = #line) async {
+    /// Assert that operations for each task happen in the exact order specified
+    private func XCTAssertTaskOrderEquals(_ taskIds: [String], expectedOrder: [Operation.Kind], file: StaticString = #file, line: UInt = #line) async {
         for id in taskIds {
             let realOrder = await timeline.operationOrder(for: id)
             XCTAssertEqual(realOrder, expectedOrder, "Order for task \(id) is incorrect", file: file, line: line)
         }
     }
     
+    /// Assert that for every task a given operation occurs before another operation
+    private func XCTAssertOperationBefore(_ taskIds: [String], operation: Operation.Kind, before: Operation.Kind, file: StaticString = #file, line: UInt = #line) async {
+        for id in taskIds {
+            let realOrder = await timeline.operationOrder(for: id)
+            guard let index = realOrder.firstIndex(of: operation), let beforeIndex = realOrder.firstIndex(of: before) else {
+                XCTFail("Cannot find given operations", file: file, line: line)
+                return
+            }
+            XCTAssertLessThan(index, beforeIndex, "Operation \(operation) does not happen before \(before)", file: file, line: line)
+        }
+    }
+    
+    /// Assert that the operations of different tasks overlap (i.e. second task starts before the first task finishes)
     private func XCTAssertTasksOverlap(_ taskIds: [String], file: StaticString = #file, line: UInt = #line) async {
         for i in 0 ..< taskIds.count {
             for j in i + 1 ..< taskIds.count {

        }
        
        await waitForExpectations(timeout: 1)
        await XCTAssertTaskOrderEqual(taskIds, expectedOrder: [.nonTask, .taskStart, .taskEnd])
    }
    
    // MARK: - Execution helpers

    
    /// An operation within or outside of a task used to assert test results
    struct Operation: Hashable {
        enum Kind: String, CaseIterable, CustomStringConvertible {
            case taskStart
            case taskEnd
            case nonTask
            
            var description: String {
                return rawValue
            }
        }
        
        let id: String
