Skip to content

Testing

Cyrus Chan edited this page Jan 17, 2024 · 2 revisions

OgHref started to offer testing libararies since 3.3.0 in oghref_model and 4.0.0 in oghref_builder which enables developers to simulate expected behaviours of fetching HTML content in isolated environments. In this page, it covers complete turorials from setup a MockOgHrefClient for MetaFetchTester to writing test codes in test directory.

(Optional) Customize content for MockOgHrefClient

Note

This fragment is designed for developers who prefer using custom content.

Familiarizing which URL will be "responded" expectedly is the most critical steps when executing testes that the outcome should be unchanged unless any modification made by developers. Therefore, a client which emulating access behaviours of HTTP(S) is required.

MockOgHrefClient is a client which has same bahaviours as MockClient but simplified configuration of handling responded content which fulfilled requirements of MetaFetch. It's constructor provided two parameters namely contentLinker for mapping content from corresponded Uri and contentType for identify catrgory of incoming response's content type.

For the content in contentLinker, it typically is a string with HTML format that it is ideal that declared as dedicated variable with multiline notation which contains actual HTML format:

/* 
    The content is declared as string with multiline notation 
    which preferred to assigned as variable first for better
    readability.
*/
const String  = r"""<!DOCTYPE html>
<html>
    <!--Head and body of HTML files-->
</html>
"""

Then, define a function which returns new instance of MockOgHrefClient with mapped content which will be used when attaching instance or open browser emulation:

MockOgHrefClient createCustomMockClient() {
    final Map<Uri, String> linker = {
        Uri.parse("https://example.com"): sampleContent
    };

    return MockOgHrefClient(linker);
}

Writing test codes

When writing test codes, there are fews procedures must be followed to ensure incoming taskes executed under managments. Any missed steps can leads to testing broken or got unexpected result which not under predictions.

Setup before testing

Attach instance for MetaFetch

Setting instance of MetaFetch is mandated that it not only retains existed parser and current setting, but also used by OgHrefBuilder to generate content. Therefore, it allows reusing same instance with existed preferences made during various taskes.

There are two options to attach instance which is using sample from this repository or using custom content.

Note

It is possible to uses setUp instead of setUpAll if required to reset all preferences equally for every testes. However, it is not recommended especially implementing test with the builder.

Using sample contents

Simply assign MetaFetch.forTest() to MetaFetch.instance:

setUpAll(() {
    MetaFetch.instance = MetaFetch.forTest();
});
Using customized contents

Important

This section's example codes is reusing from custom content. Please visit this section first before attaching instance.

Assign MetaFetchTester with a function for constructing MockOgHrefClient as a parameter of the tester's constructor into MetaFetch.instance:

setUpAll(() {
    MetaFetch.instance = MetaFetchTester(createCustomMockClient);
});

Attach instance for url_launcher library

Note

This section only applied for oghref_builder only.

Caution

Ignoring this step will causes unwanted behaviours done out of Flutter scopes and possibly no longer worked properly if executing under continous integration.

OgHrefBuilder bundles a callback for opening web browser and direct to given URL. By default, it operated by system calling which rely on real network rather than mocked one. Therefore, the replicated launcher also should be defined before running testes.

Likes attaching MetaFetch's instance, there are two approaches depending which content is used namely given sample or customized one.

Emulateing open link from sample content

Call setupMockInstances without parsing arguments:

setUpAll(() {
    setupMockInstances();
});
Emulateing open link from custom content

Important

This section's example codes is reusing from custom content. Please visit this section first before attaching instance.

Call setupMockInstances and parse the function which constructs new instance of MockClient. The functions can be reused the same function for MockOgHrefClient or another MockClient that does not shared the same content from MockOgHrefClient.

Reusing MockOgHrefClient
setUpAll(() {
    setupMockInstances(createCustomMockClient);
});
Custom MockClient implementation

The returned of response must includes request object and content type in the header.

setUpAll(() {
    setupMockInstances(() => MockClient((Request req) async {
        final String body = "body";
        final int status = 200;
        
        return Response(body, status, request: req, headers: const {"content-type": "text/plain"});
    }));
});

During test

Pumping widget

Note

This section only applied for oghref_builder only.

It requires pump twice when OgHrefBuilder is appeared in widget tree that the first pump should be happened instantly that the builder is fetching metadata found from provided URL and the second pump for rendered content when metadata has been obtained or encountered error during fetching process.

The first pump can be either pumpWidget or pump depending any additional interaction applied for realistic experiences.

The second pump must be called immediately after the first pump with delay applied which is the longest duration that mock client will yield responde between 250ms to 1s. And the pumped widget should be completed all fetching process and show applied widgets.

import 'package:flutter_test/flutter_test.dart';
import 'package:oghref_builder/oghref_builder.dart';
import 'package:oghref_builder/testing.dart' hide deferPump;
import 'package:oghref_builder/testing.dart' as oghref_builder_test show deferPump;

void main() {
    setUpAll(() {
        // Setup instance here.
    });
    test("(Title)", (WidgetTester tester) async {
        await tester.pumpWidget(const TestApp()); // The builder included as child widget already.
        await tester.pump(oghref_builder_test.deferPump);

        // Do expectation below.
    });
}