summaryrefslogtreecommitdiff
path: root/test/webhelper/testWebActions.js
blob: b2ddaf0941a5805f95508b1747e523f8d64b6eb4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
const Endless = imports.gi.Endless;
const Gio = imports.gi.Gio;
const GLib = imports.gi.GLib;
const Gtk = imports.gi.Gtk;
const Lang = imports.lang;
const WebHelper = imports.webhelper;
const WebKit = imports.gi.WebKit;

const WebActionTestApplication = new Lang.Class({
    Name: 'WebActionTestApplication',
    Extends: WebHelper.Application,

    vfunc_startup: function() {
        this.parent();
        this.webview = new WebKit.WebView();
        this.webview.connect('navigation-policy-decision-requested',
            Lang.bind(this, this.web_actions_handler));
        let string = ('<html><head><meta http-equiv="refresh" content="0;url=' +
            this.webActionToTest + '"></head><body></body></html>');
        this.webview.load_string(string, 'text/html', 'UTF-8', 'file://');
        this.win = new Endless.Window({
            application: this
        });
        this.scrolled = new Gtk.ScrolledWindow();
        this.scrolled.add(this.webview);
        this.win.page_manager.add(this.scrolled);

        // Add an upper bound on how long the app runs, in case app.quit() does
        // not get called
        GLib.timeout_add_seconds(GLib.PRIORITY_HIGH, 5, Lang.bind(this, function() {
            this.quit();
        }));
    }
});

// TODO: These tests depend on a running X Server and Window Manager. That means
// that they are not runnable in a continuous-integration server
describe("Web Actions Bindings", function() {
    let app;
    let webActionSpy;
    
    beforeEach(function() {
        // Generate a unique ID for each app instance that we test
        let fake_pid = GLib.random_int();
        // FIXME In this version of GJS there is no Posix module, so fake the PID
        let id_string = 'com.endlessm.webhelper.test' + GLib.get_real_time() + fake_pid;
        app = new WebActionTestApplication({
            application_id: id_string
        });
        webActionSpy = jasmine.createSpy('quitAction').and.callFake(function() {
            app.quit();
        });
    });
    
    let RunApplicationWithWebAction = function(app, action) {
        app.webActionToTest = action;
        app.run([]);
    }
    it("has a working quitApplication uri upon defining quitApplication as a string", function() {
        app.define_web_action('quitApplication', webActionSpy);
        RunApplicationWithWebAction(app, 'endless://quitApplication');

        expect(webActionSpy).toHaveBeenCalled();
    });

    it("is called with a parameter", function() {
        app.define_web_action('getParameterAndQuit', webActionSpy);
        RunApplicationWithWebAction(app, 'endless://getParameterAndQuit?param=value');

        expect(webActionSpy).toHaveBeenCalledWith(new jasmine.ObjectContaining({ param: 'value' }));
    });

    it("can be called with many parameters", function() {
        app.define_web_action('getParametersAndQuit', webActionSpy);
        RunApplicationWithWebAction(app, 'endless://getParametersAndQuit?first=thefirst&second=thesecond&third=thethird');

        expect(webActionSpy).toHaveBeenCalledWith(new jasmine.ObjectContaining({
            first: 'thefirst',
            second: 'thesecond',
            third: 'thethird'
        }));
    });

    it("decodes parameter URI names", function() {
        app.define_web_action('getUriDecodedParameterAndQuit', webActionSpy);
        RunApplicationWithWebAction(app, 'endless://getUriDecodedParameterAndQuit?p%C3%A4r%C3%A4m%F0%9F%92%A9=value');

        expect(webActionSpy).toHaveBeenCalledWith(new jasmine.ObjectContaining({
            'päräm💩' : 'value'
        }));
    });

    it("decodes parameter URI values", function() {
        app.define_web_action('getUriDecodedParameterValueAndQuit', webActionSpy);
        RunApplicationWithWebAction(app, 'endless://getUriDecodedParameterValueAndQuit?param=v%C3%A1lu%C3%A9%F0%9F%92%A9');

        expect(webActionSpy).toHaveBeenCalledWith(new jasmine.ObjectContaining({
            param : 'válué💩'
        }));
    });

    // We currently can't catch exceptions across GObject-Introspection callbacks
    xit('bad action is not called', function() {
        expect(function() { RunApplicationWithWebAction(app, 'endless://nonexistentWebAction') }).toThrow();
    });

    describe("with blank parameters", function() {
        beforeEach(function() {
            app.define_web_action('getBlankValueAndQuit', webActionSpy);
            RunApplicationWithWebAction(app, 'endless://getBlankValueAndQuit?param=');
        });

        it("can be called", function() {
            expect(webActionSpy).toHaveBeenCalled();
        });

        it("is called with a paramater that is an empty string", function() {
            expect(webActionSpy).toHaveBeenCalledWith(new jasmine.ObjectContaining({ 
                'param' : ''
            }));
        });
    });

    it("URI decodes the action", function() {
        app.define_web_action('äction💩Quit', webActionSpy);
        RunApplicationWithWebAction(app, 'endless://%C3%A4ction%F0%9F%92%A9Quit');
        expect(webActionSpy).toHaveBeenCalled();
    });

    it("allows web actions to be defined as object properties", function() {
        app.define_web_actions({
            quitApplication: webActionSpy
        });
 
        RunApplicationWithWebAction(app, 'endless://quitApplication');

        expect(webActionSpy).toHaveBeenCalled();
    });

    it("throws an error when trying to define an action that is not a function", function() {
        expect(function() {
            app.define_web_action('action', {});
        }).toThrow();
    });
});