Uploaded Test files
This commit is contained in:
parent
f584ad9d97
commit
2e81cb7d99
16627 changed files with 2065359 additions and 102444 deletions
0
venv/Lib/site-packages/notebook/tests/__init__.py
Normal file
0
venv/Lib/site-packages/notebook/tests/__init__.py
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
58
venv/Lib/site-packages/notebook/tests/base/highlight.js
Normal file
58
venv/Lib/site-packages/notebook/tests/base/highlight.js
Normal file
|
@ -0,0 +1,58 @@
|
|||
casper.notebook_test(function () {
|
||||
this.on('remote.callback', function(data){
|
||||
if(data.error_expected){
|
||||
that.test.assertEquals(
|
||||
data.error,
|
||||
true,
|
||||
"!highlight: " + data.provided + " errors"
|
||||
);
|
||||
}else{
|
||||
that.test.assertEquals(
|
||||
data.observed,
|
||||
data.expected,
|
||||
"highlight: " + data.provided + " as " + data.expected
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
var that = this;
|
||||
// syntax highlighting
|
||||
[
|
||||
{to: "gfm"},
|
||||
{to: "python"},
|
||||
{to: "ipython"},
|
||||
{to: "ipythongfm"},
|
||||
{to: "text/x-markdown", from: [".md"]},
|
||||
{to: "text/x-python", from: [".py", "Python"]},
|
||||
{to: "application/json", from: ["json", "JSON"]},
|
||||
{to: "text/x-ruby", from: [".rb", "ruby", "Ruby"]},
|
||||
{to: "application/ld+json", from: ["json-ld", "JSON-LD"]},
|
||||
{from: [".pyc"], error: true},
|
||||
{from: ["../"], error: true},
|
||||
{from: ["//"], error: true},
|
||||
].map(function (mode) {
|
||||
(mode.from || []).concat(mode.to || []).map(function(from){
|
||||
casper.evaluate(function(from, expected, error_expected){
|
||||
IPython.utils.requireCodeMirrorMode(from, function(observed){
|
||||
window.callPhantom({
|
||||
provided: from,
|
||||
expected: expected,
|
||||
observed: observed,
|
||||
error_expected: error_expected
|
||||
});
|
||||
}, function(error){
|
||||
window.callPhantom({
|
||||
provided: from,
|
||||
expected: expected,
|
||||
error: true,
|
||||
error_expected: error_expected
|
||||
});
|
||||
});
|
||||
}, {
|
||||
from: from,
|
||||
expected: mode.to,
|
||||
error_expected: mode.error
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
95
venv/Lib/site-packages/notebook/tests/base/keyboard.js
Normal file
95
venv/Lib/site-packages/notebook/tests/base/keyboard.js
Normal file
|
@ -0,0 +1,95 @@
|
|||
|
||||
|
||||
var normalized_shortcuts = [
|
||||
'ctrl-shift-m',
|
||||
'alt-meta-p',
|
||||
];
|
||||
|
||||
var to_normalize = [
|
||||
['shift-%', 'shift-5'],
|
||||
['ShiFT-MeTa-CtRl-AlT-m', 'alt-ctrl-meta-shift-m'],
|
||||
];
|
||||
|
||||
var unshifted = "` 1 2 3 4 5 6 7 8 9 0 - = q w e r t y u i o p [ ] \\ a s d f g h j k l ; ' z x c v b n m , . /";
|
||||
// shifted = '~ ! @ # $ % ^ & * ( ) _ + Q W E R T Y U I O P { } | A S D F G H J K L : " Z X C V B N M < > ?';
|
||||
|
||||
var ambiguous_expect = function(ch){
|
||||
// `-` is ambiguous in shortcut context as a separator, so map it to `minus`
|
||||
if(ch === '-'){
|
||||
return 'minus';
|
||||
}
|
||||
return ch;
|
||||
};
|
||||
|
||||
casper.notebook_test(function () {
|
||||
var that = this;
|
||||
|
||||
this.then(function () {
|
||||
this.each(unshifted.split(' '), function (self, item) {
|
||||
var result = this.evaluate(function (sc) {
|
||||
var e = IPython.keyboard.shortcut_to_event(sc);
|
||||
var sc2 = IPython.keyboard.event_to_shortcut(e);
|
||||
return sc2;
|
||||
}, item);
|
||||
this.test.assertEquals(result, ambiguous_expect(item), 'Shortcut to event roundtrip: '+item);
|
||||
});
|
||||
});
|
||||
|
||||
this.then(function () {
|
||||
this.each(to_normalize, function (self, item) {
|
||||
var result = this.evaluate(function (pair) {
|
||||
return IPython.keyboard.normalize_shortcut(pair[0]);
|
||||
}, item);
|
||||
this.test.assertEquals(result, item[1], 'Normalize shortcut: '+item[0]);
|
||||
});
|
||||
});
|
||||
|
||||
this.then(function () {
|
||||
this.each(normalized_shortcuts, function (self, item) {
|
||||
var result = this.evaluate(function (sc) {
|
||||
var e = IPython.keyboard.shortcut_to_event(sc);
|
||||
var sc2 = IPython.keyboard.event_to_shortcut(e);
|
||||
return sc2;
|
||||
}, item);
|
||||
this.test.assertEquals(result, item, 'Shortcut to event roundtrip: '+item);
|
||||
});
|
||||
});
|
||||
|
||||
this.then(function(){
|
||||
|
||||
var shortcuts_test = {
|
||||
'i,e,e,e,e,e' : '[[5E]]',
|
||||
'i,d,d,q,d' : '[[TEST1]]',
|
||||
'i,d,d' : '[[TEST1 WILL BE SHADOWED]]',
|
||||
'i,d,k' : '[[SHOULD SHADOW TEST2]]',
|
||||
'i,d,k,r,q' : '[[TEST2 NOT SHADOWED]]',
|
||||
';,up,down,up,down,left,right,left,right,b,a' : '[[KONAMI]]',
|
||||
'ctrl-x,meta-c,meta-b,u,t,t,e,r,f,l,y' : '[[XKCD]]'
|
||||
|
||||
};
|
||||
|
||||
that.msgs = [];
|
||||
that.on('remote.message', function(msg) {
|
||||
that.msgs.push(msg);
|
||||
});
|
||||
that.evaluate(function (obj) {
|
||||
for(var k in obj){
|
||||
if ({}.hasOwnProperty.call(obj, k)) {
|
||||
IPython.keyboard_manager.command_shortcuts.add_shortcut(k, function(){console.log(obj[k]);});
|
||||
}
|
||||
}
|
||||
}, shortcuts_test);
|
||||
|
||||
var longer_first = false;
|
||||
var longer_last = false;
|
||||
for(var m in that.msgs){
|
||||
if ({}.hasOwnProperty.call(that.msgs, m)) {
|
||||
longer_first = longer_first||(that.msgs[m].match(/you are overriting/)!= null);
|
||||
longer_last = longer_last ||(that.msgs[m].match(/will be shadowed/) != null);
|
||||
}
|
||||
}
|
||||
this.test.assert(longer_first, 'no warning if registering shorter shortcut');
|
||||
this.test.assert(longer_last , 'no warning if registering longer shortcut');
|
||||
});
|
||||
|
||||
});
|
45
venv/Lib/site-packages/notebook/tests/base/misc.js
Normal file
45
venv/Lib/site-packages/notebook/tests/base/misc.js
Normal file
|
@ -0,0 +1,45 @@
|
|||
|
||||
//
|
||||
// Miscellaneous javascript tests
|
||||
//
|
||||
casper.notebook_test(function () {
|
||||
var jsver = this.evaluate(function () {
|
||||
var cell = IPython.notebook.get_cell(0);
|
||||
cell.set_text('import notebook; print(notebook.__version__)');
|
||||
cell.execute();
|
||||
return IPython.version;
|
||||
});
|
||||
|
||||
this.wait_for_output(0);
|
||||
|
||||
// refactor this into just a get_output(0)
|
||||
this.then(function () {
|
||||
var result = this.get_output_cell(0);
|
||||
this.test.assertEquals(result.text.trim(), jsver, 'IPython.version in JS matches server-side.');
|
||||
});
|
||||
|
||||
// verify that requirejs loads the same CodeCell prototype at runtime as build time
|
||||
this.thenEvaluate(function () {
|
||||
require(['notebook/js/codecell'], function (codecell) {
|
||||
codecell.CodeCell.prototype.test = function () {
|
||||
return 'ok';
|
||||
}
|
||||
window._waitForMe = true;
|
||||
})
|
||||
})
|
||||
|
||||
this.waitFor(function () {
|
||||
return this.evaluate(function () {
|
||||
return window._waitForMe;
|
||||
});
|
||||
})
|
||||
|
||||
this.then(function () {
|
||||
var result = this.evaluate(function () {
|
||||
var cell = Jupyter.notebook.get_cell(0);
|
||||
return cell.test();
|
||||
});
|
||||
this.test.assertEquals(result, 'ok', "runtime-requirejs loads the same modules")
|
||||
})
|
||||
|
||||
});
|
57
venv/Lib/site-packages/notebook/tests/base/security.js
Normal file
57
venv/Lib/site-packages/notebook/tests/base/security.js
Normal file
|
@ -0,0 +1,57 @@
|
|||
safe_tests = [
|
||||
"<p>Hi there</p>",
|
||||
'<h1 class="foo">Hi There!</h1>',
|
||||
'<a data-cite="foo">citation</a>',
|
||||
'<div><span>Hi There</span></div>',
|
||||
];
|
||||
|
||||
unsafe_tests = [
|
||||
"<script>alert(999);</script>",
|
||||
'<a onmouseover="alert(999)">999</a>',
|
||||
'<a onmouseover=alert(999)>999</a>',
|
||||
'<IMG """><SCRIPT>alert("XSS")</SCRIPT>">',
|
||||
'<IMG SRC=# onmouseover="alert(999)">',
|
||||
'<<SCRIPT>alert(999);//<</SCRIPT>',
|
||||
'<SCRIPT SRC=http://ha.ckers.org/xss.js?< B >',
|
||||
'<META HTTP-EQUIV="refresh" CONTENT="0;url=data:text/html base64,PHNjcmlwdD5hbGVydCgnWFNTJyk8L3NjcmlwdD4K">',
|
||||
'<META HTTP-EQUIV="refresh" CONTENT="0; URL=http://;URL=javascript:alert(999);">',
|
||||
'<IFRAME SRC="javascript:alert(999);"></IFRAME>',
|
||||
'<IFRAME SRC=# onmouseover="alert(document.cookie)"></IFRAME>',
|
||||
'<EMBED SRC="data:image/svg+xml;base64,PHN2ZyB4bWxuczpzdmc9Imh0dH A6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcv MjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hs aW5rIiB2ZXJzaW9uPSIxLjAiIHg9IjAiIHk9IjAiIHdpZHRoPSIxOTQiIGhlaWdodD0iMjAw IiBpZD0ieHNzIj48c2NyaXB0IHR5cGU9InRleHQvZWNtYXNjcmlwdCI+YWxlcnQoIlh TUyIpOzwvc2NyaXB0Pjwvc3ZnPg==" type="image/svg+xml" AllowScriptAccess="always"></EMBED>',
|
||||
// CSS is scrubbed
|
||||
'<style src="http://untrusted/style.css"></style>',
|
||||
'<style>div#notebook { background-color: alert-red; }</style>',
|
||||
'<div style="background-color: alert-red;"></div>',
|
||||
];
|
||||
|
||||
var truncate = function (s, n) {
|
||||
// truncate a string with an ellipsis
|
||||
if (s.length > n) {
|
||||
return s.substr(0, n-3) + '...';
|
||||
} else {
|
||||
return s;
|
||||
}
|
||||
};
|
||||
|
||||
casper.notebook_test(function () {
|
||||
this.each(safe_tests, function (self, item) {
|
||||
var sanitized = self.evaluate(function (item) {
|
||||
return IPython.security.sanitize_html(item);
|
||||
}, item);
|
||||
|
||||
// string equality may be too strict, but it works for now
|
||||
this.test.assertEquals(sanitized, item, "Safe: '" + truncate(item, 32) + "'");
|
||||
});
|
||||
|
||||
this.each(unsafe_tests, function (self, item) {
|
||||
var sanitized = self.evaluate(function (item) {
|
||||
return IPython.security.sanitize_html(item);
|
||||
}, item);
|
||||
|
||||
this.test.assertNotEquals(sanitized, item,
|
||||
"Sanitized: '" + truncate(item, 32) +
|
||||
"' => '" + truncate(sanitized, 32) + "'"
|
||||
);
|
||||
this.test.assertEquals(sanitized.indexOf("alert"), -1, "alert removed");
|
||||
});
|
||||
});
|
93
venv/Lib/site-packages/notebook/tests/base/utils.js
Normal file
93
venv/Lib/site-packages/notebook/tests/base/utils.js
Normal file
|
@ -0,0 +1,93 @@
|
|||
casper.notebook_test(function () {
|
||||
// Test fixConsole
|
||||
// Note, \u001b is the unicode notation of octal \033 which is not officially in js
|
||||
var input = [
|
||||
"\u001b[0m[\u001b[0minfo\u001b[0m] \u001b[0mtext\u001b[0m",
|
||||
"\u001b[0m[\u001b[33mwarn\u001b[0m] \u001b[0m\tmore text\u001b[0m",
|
||||
"\u001b[0m[\u001b[33mwarn\u001b[0m] \u001b[0m https://some/url/to/a/file.ext\u001b[0m",
|
||||
"\u001b[0m[\u001b[31merror\u001b[0m] \u001b[0m\u001b[0m",
|
||||
"\u001b[0m[\u001b[31merror\u001b[0m] \u001b[0m\teven more text\u001b[0m",
|
||||
"\u001b[?25hBuilding wheels for collected packages: scipy",
|
||||
"\x1b[38;5;28;01mtry\x1b[39;00m",
|
||||
"\u001b[0m[\u001b[31merror\u001b[0m] \u001b[0m\t\tand more more text\u001b[0m",
|
||||
"normal\x1b[43myellowbg\x1b[35mmagentafg\x1b[1mbold\x1b[49mdefaultbg\x1b[39mdefaultfg\x1b[22mnormal",
|
||||
].join("\n");
|
||||
|
||||
var output = [
|
||||
"[info] text",
|
||||
'[<span class="ansi-yellow-fg">warn</span>] \tmore text',
|
||||
'[<span class="ansi-yellow-fg">warn</span>] https://some/url/to/a/file.ext',
|
||||
'[<span class="ansi-red-fg">error</span>] ',
|
||||
'[<span class="ansi-red-fg">error</span>] \teven more text',
|
||||
"Building wheels for collected packages: scipy",
|
||||
'<span class="ansi-bold" style="color: rgb(0,135,0)">try</span>',
|
||||
'[<span class="ansi-red-fg">error</span>] \t\tand more more text',
|
||||
'normal<span class="ansi-yellow-bg">yellowbg</span><span class="ansi-magenta-fg ansi-yellow-bg">magentafg</span><span class="ansi-magenta-intense-fg ansi-yellow-bg ansi-bold">bold</span><span class="ansi-magenta-intense-fg ansi-bold">defaultbg</span><span class="ansi-bold">defaultfg</span>normal',
|
||||
].join("\n");
|
||||
|
||||
var result = this.evaluate(function (input) {
|
||||
return IPython.utils.fixConsole(input);
|
||||
}, input);
|
||||
|
||||
this.test.assertEquals(result, output, "IPython.utils.fixConsole() handles [0m correctly");
|
||||
|
||||
// Test fixOverwrittenChars
|
||||
var overwriting_test_cases = [
|
||||
{input: "ABC\rDEF", result: "DEF"},
|
||||
{input: "ABC\r\nDEF", result: "ABC\nDEF"},
|
||||
{input: "123\b456", result: "12456"},
|
||||
{input: "123\n\b456", result: "123\n\b456"},
|
||||
{input: "\b456", result: "\b456"}
|
||||
];
|
||||
|
||||
var that = this;
|
||||
overwriting_test_cases.forEach(function(testcase){
|
||||
var result = that.evaluate(function (input) {
|
||||
return IPython.utils.fixOverwrittenChars(input);
|
||||
}, testcase.input);
|
||||
that.test.assertEquals(result, testcase.result, "Overwriting characters processed");
|
||||
});
|
||||
|
||||
var input = [
|
||||
'hasrn\r\n',
|
||||
'hasn\n',
|
||||
'\n',
|
||||
'abcdef\r',
|
||||
'hello\n',
|
||||
'ab3\r',
|
||||
'x2\r\r',
|
||||
'1\r',
|
||||
].join('');
|
||||
|
||||
var output = [
|
||||
'hasrn\n',
|
||||
'hasn\n',
|
||||
'\n',
|
||||
'hellof\n',
|
||||
'123\r'
|
||||
].join('');
|
||||
|
||||
var result = this.evaluate(function (input) {
|
||||
return IPython.utils.fixCarriageReturn(input);
|
||||
}, input);
|
||||
|
||||
this.test.assertEquals(result, output, "IPython.utils.fixCarriageReturns works");
|
||||
|
||||
// Test load_extensions
|
||||
|
||||
this.thenEvaluate(function() {
|
||||
define('nbextensions/a', [], function() { window.a = true; });
|
||||
define('nbextensions/c', [], function() { window.c = true; });
|
||||
require(['base/js/utils'], function(utils) {
|
||||
utils.load_extensions('a', 'b', 'c');
|
||||
});
|
||||
}).then(function() {
|
||||
this.waitFor(function() {
|
||||
return this.evaluate(function() { return window.a; });
|
||||
});
|
||||
|
||||
this.waitFor(function() {
|
||||
return this.evaluate(function() { return window.a; });
|
||||
});
|
||||
});
|
||||
});
|
251
venv/Lib/site-packages/notebook/tests/launchnotebook.py
Normal file
251
venv/Lib/site-packages/notebook/tests/launchnotebook.py
Normal file
|
@ -0,0 +1,251 @@
|
|||
"""Base class for notebook tests."""
|
||||
|
||||
from __future__ import print_function
|
||||
|
||||
from binascii import hexlify
|
||||
from contextlib import contextmanager
|
||||
import errno
|
||||
import os
|
||||
import sys
|
||||
from threading import Thread, Event
|
||||
import time
|
||||
from unittest import TestCase
|
||||
|
||||
pjoin = os.path.join
|
||||
|
||||
from unittest.mock import patch
|
||||
|
||||
import requests
|
||||
from tornado.ioloop import IOLoop
|
||||
import zmq
|
||||
|
||||
import jupyter_core.paths
|
||||
from traitlets.config import Config
|
||||
from ..notebookapp import NotebookApp, urlencode_unix_socket
|
||||
from ..utils import url_path_join
|
||||
from ipython_genutils.tempdir import TemporaryDirectory
|
||||
|
||||
MAX_WAITTIME = 30 # seconds to wait for notebook server to start
|
||||
POLL_INTERVAL = 0.1 # time between attempts
|
||||
|
||||
# TimeoutError is a builtin on Python 3. This can be removed when we stop
|
||||
# supporting Python 2.
|
||||
class TimeoutError(Exception):
|
||||
pass
|
||||
|
||||
class NotebookTestBase(TestCase):
|
||||
"""A base class for tests that need a running notebook.
|
||||
|
||||
This create some empty config and runtime directories
|
||||
and then starts the notebook server with them.
|
||||
"""
|
||||
|
||||
port = 12341
|
||||
config = None
|
||||
# run with a base URL that would be escaped,
|
||||
# to test that we don't double-escape URLs
|
||||
url_prefix = '/a%40b/'
|
||||
|
||||
@classmethod
|
||||
def wait_until_alive(cls):
|
||||
"""Wait for the server to be alive"""
|
||||
url = cls.base_url() + 'api/contents'
|
||||
for _ in range(int(MAX_WAITTIME/POLL_INTERVAL)):
|
||||
try:
|
||||
cls.fetch_url(url)
|
||||
except Exception as e:
|
||||
if not cls.notebook_thread.is_alive():
|
||||
raise RuntimeError("The notebook server failed to start") from e
|
||||
time.sleep(POLL_INTERVAL)
|
||||
else:
|
||||
return
|
||||
|
||||
raise TimeoutError("The notebook server didn't start up correctly.")
|
||||
|
||||
@classmethod
|
||||
def wait_until_dead(cls):
|
||||
"""Wait for the server process to terminate after shutdown"""
|
||||
cls.notebook_thread.join(timeout=MAX_WAITTIME)
|
||||
if cls.notebook_thread.is_alive():
|
||||
raise TimeoutError("Undead notebook server")
|
||||
|
||||
@classmethod
|
||||
def auth_headers(cls):
|
||||
headers = {}
|
||||
if cls.token:
|
||||
headers['Authorization'] = 'token %s' % cls.token
|
||||
return headers
|
||||
|
||||
@staticmethod
|
||||
def fetch_url(url):
|
||||
return requests.get(url)
|
||||
|
||||
@classmethod
|
||||
def request(cls, verb, path, **kwargs):
|
||||
"""Send a request to my server
|
||||
|
||||
with authentication and everything.
|
||||
"""
|
||||
headers = kwargs.setdefault('headers', {})
|
||||
headers.update(cls.auth_headers())
|
||||
response = requests.request(verb,
|
||||
url_path_join(cls.base_url(), path),
|
||||
**kwargs)
|
||||
return response
|
||||
|
||||
@classmethod
|
||||
def get_patch_env(cls):
|
||||
return {
|
||||
'HOME': cls.home_dir,
|
||||
'PYTHONPATH': os.pathsep.join(sys.path),
|
||||
'IPYTHONDIR': pjoin(cls.home_dir, '.ipython'),
|
||||
'JUPYTER_NO_CONFIG': '1', # needed in the future
|
||||
'JUPYTER_CONFIG_DIR' : cls.config_dir,
|
||||
'JUPYTER_DATA_DIR' : cls.data_dir,
|
||||
'JUPYTER_RUNTIME_DIR': cls.runtime_dir,
|
||||
}
|
||||
|
||||
@classmethod
|
||||
def get_argv(cls):
|
||||
return []
|
||||
|
||||
@classmethod
|
||||
def get_bind_args(cls):
|
||||
return dict(port=cls.port)
|
||||
|
||||
@classmethod
|
||||
def setup_class(cls):
|
||||
cls.tmp_dir = TemporaryDirectory()
|
||||
def tmp(*parts):
|
||||
path = os.path.join(cls.tmp_dir.name, *parts)
|
||||
try:
|
||||
os.makedirs(path)
|
||||
except OSError as e:
|
||||
if e.errno != errno.EEXIST:
|
||||
raise
|
||||
return path
|
||||
|
||||
cls.home_dir = tmp('home')
|
||||
data_dir = cls.data_dir = tmp('data')
|
||||
config_dir = cls.config_dir = tmp('config')
|
||||
runtime_dir = cls.runtime_dir = tmp('runtime')
|
||||
cls.notebook_dir = tmp('notebooks')
|
||||
cls.env_patch = patch.dict('os.environ', cls.get_patch_env())
|
||||
cls.env_patch.start()
|
||||
# Patch systemwide & user-wide data & config directories, to isolate
|
||||
# the tests from oddities of the local setup. But leave Python env
|
||||
# locations alone, so data files for e.g. nbconvert are accessible.
|
||||
# If this isolation isn't sufficient, you may need to run the tests in
|
||||
# a virtualenv or conda env.
|
||||
cls.path_patch = patch.multiple(
|
||||
jupyter_core.paths,
|
||||
SYSTEM_JUPYTER_PATH=[tmp('share', 'jupyter')],
|
||||
SYSTEM_CONFIG_PATH=[tmp('etc', 'jupyter')],
|
||||
)
|
||||
cls.path_patch.start()
|
||||
|
||||
config = cls.config or Config()
|
||||
config.NotebookNotary.db_file = ':memory:'
|
||||
|
||||
cls.token = hexlify(os.urandom(4)).decode('ascii')
|
||||
|
||||
started = Event()
|
||||
def start_thread():
|
||||
try:
|
||||
bind_args = cls.get_bind_args()
|
||||
app = cls.notebook = NotebookApp(
|
||||
port_retries=0,
|
||||
open_browser=False,
|
||||
config_dir=cls.config_dir,
|
||||
data_dir=cls.data_dir,
|
||||
runtime_dir=cls.runtime_dir,
|
||||
notebook_dir=cls.notebook_dir,
|
||||
base_url=cls.url_prefix,
|
||||
config=config,
|
||||
allow_root=True,
|
||||
token=cls.token,
|
||||
**bind_args
|
||||
)
|
||||
if 'asyncio' in sys.modules:
|
||||
app._init_asyncio_patch()
|
||||
import asyncio
|
||||
asyncio.set_event_loop(asyncio.new_event_loop())
|
||||
# don't register signal handler during tests
|
||||
app.init_signal = lambda : None
|
||||
# clear log handlers and propagate to root for nose to capture it
|
||||
# needs to be redone after initialize, which reconfigures logging
|
||||
app.log.propagate = True
|
||||
app.log.handlers = []
|
||||
app.initialize(argv=cls.get_argv())
|
||||
app.log.propagate = True
|
||||
app.log.handlers = []
|
||||
loop = IOLoop.current()
|
||||
loop.add_callback(started.set)
|
||||
app.start()
|
||||
finally:
|
||||
# set the event, so failure to start doesn't cause a hang
|
||||
started.set()
|
||||
app.session_manager.close()
|
||||
cls.notebook_thread = Thread(target=start_thread)
|
||||
cls.notebook_thread.daemon = True
|
||||
cls.notebook_thread.start()
|
||||
started.wait()
|
||||
cls.wait_until_alive()
|
||||
|
||||
@classmethod
|
||||
def teardown_class(cls):
|
||||
cls.notebook.stop()
|
||||
cls.wait_until_dead()
|
||||
cls.env_patch.stop()
|
||||
cls.path_patch.stop()
|
||||
cls.tmp_dir.cleanup()
|
||||
# cleanup global zmq Context, to ensure we aren't leaving dangling sockets
|
||||
def cleanup_zmq():
|
||||
zmq.Context.instance().term()
|
||||
t = Thread(target=cleanup_zmq)
|
||||
t.daemon = True
|
||||
t.start()
|
||||
t.join(5) # give it a few seconds to clean up (this should be immediate)
|
||||
# if term never returned, there's zmq stuff still open somewhere, so shout about it.
|
||||
if t.is_alive():
|
||||
raise RuntimeError("Failed to teardown zmq Context, open sockets likely left lying around.")
|
||||
|
||||
@classmethod
|
||||
def base_url(cls):
|
||||
return 'http://localhost:%i%s' % (cls.port, cls.url_prefix)
|
||||
|
||||
|
||||
class UNIXSocketNotebookTestBase(NotebookTestBase):
|
||||
# Rely on `/tmp` to avoid any Linux socket length max buffer
|
||||
# issues. Key on PID for process-wise concurrency.
|
||||
sock = '/tmp/.notebook.%i.sock' % os.getpid()
|
||||
|
||||
@classmethod
|
||||
def get_bind_args(cls):
|
||||
return dict(sock=cls.sock)
|
||||
|
||||
@classmethod
|
||||
def base_url(cls):
|
||||
return '%s%s' % (urlencode_unix_socket(cls.sock), cls.url_prefix)
|
||||
|
||||
@staticmethod
|
||||
def fetch_url(url):
|
||||
# Lazily import so it is not required at the module level
|
||||
if os.name != 'nt':
|
||||
import requests_unixsocket
|
||||
with requests_unixsocket.monkeypatch():
|
||||
return requests.get(url)
|
||||
|
||||
|
||||
@contextmanager
|
||||
def assert_http_error(status, msg=None):
|
||||
try:
|
||||
yield
|
||||
except requests.HTTPError as e:
|
||||
real_status = e.response.status_code
|
||||
assert real_status == status, \
|
||||
"Expected status %d, got %d" % (status, real_status)
|
||||
if msg:
|
||||
assert msg in str(e), e
|
||||
else:
|
||||
assert False, "Expected HTTP error status"
|
|
@ -0,0 +1 @@
|
|||
console.log('z');
|
192
venv/Lib/site-packages/notebook/tests/notebook/attachments.js
Normal file
192
venv/Lib/site-packages/notebook/tests/notebook/attachments.js
Normal file
|
@ -0,0 +1,192 @@
|
|||
//
|
||||
// Test cell attachments
|
||||
//
|
||||
var fs = require('fs');
|
||||
casper.notebook_test(function () {
|
||||
// -- Test the Edit->Insert Image menu to insert new attachments
|
||||
"use strict";
|
||||
casper.test.info("Testing attachments insertion through the menuitem");
|
||||
|
||||
this.viewport(1024, 768);
|
||||
|
||||
// Click on menuitem
|
||||
var selector = '#insert_image > a';
|
||||
this.waitForSelector(selector);
|
||||
this.thenEvaluate(function(sel) {
|
||||
Jupyter.notebook.to_markdown();
|
||||
var cell = Jupyter.notebook.get_selected_cell();
|
||||
cell.set_text("");
|
||||
cell.unrender();
|
||||
|
||||
$(sel).click();
|
||||
}, selector);
|
||||
// Wait for the dialog to be shown
|
||||
this.waitUntilVisible(".modal-body");
|
||||
this.wait(200);
|
||||
|
||||
// Select the image file to insert
|
||||
|
||||
// For some reason, this doesn't seem to work in a reliable way in
|
||||
// phantomjs. So we manually set the input's files attribute
|
||||
//this.page.uploadFile('.modal-body input[name=file]', 'test.png')
|
||||
this.then(function() {
|
||||
var fname = 'notebook/tests/_testdata/black_square_22.png';
|
||||
if (!fs.exists(fname)) {
|
||||
this.test.fail(
|
||||
" does not exist, are you running the tests " +
|
||||
"from the root directory ? "
|
||||
);
|
||||
}
|
||||
this.fill('form#insert-image-form', {'file': fname});
|
||||
});
|
||||
|
||||
// Validate and render the markdown cell
|
||||
this.thenClick('#btn_ok');
|
||||
this.thenEvaluate(function() {
|
||||
Jupyter.notebook.get_cell(0).render();
|
||||
});
|
||||
this.wait(300);
|
||||
// Check that an <img> tag has been inserted and that it contains the
|
||||
// image
|
||||
this.then(function() {
|
||||
var img = this.evaluate(function() {
|
||||
var cell = Jupyter.notebook.get_cell(0);
|
||||
var img = $("div.text_cell_render").find("img");
|
||||
return {
|
||||
src: img.attr("src"),
|
||||
width: img.width(),
|
||||
height: img.height(),
|
||||
};
|
||||
});
|
||||
this.test.assertType(img, "object", "Image('image/png')");
|
||||
this.test.assertEquals(img.src.split(',')[0],
|
||||
"data:image/png;base64",
|
||||
"Image data-uri prefix");
|
||||
this.test.assertEquals(img.width, 2, "width == 2");
|
||||
this.test.assertEquals(img.height, 2, "height == 2");
|
||||
});
|
||||
|
||||
//this.then(function() {
|
||||
//this.capture('test.png');
|
||||
//});
|
||||
|
||||
// -- Use the Edit->Copy/Paste Cell Attachments menu items
|
||||
selector = '#copy_cell_attachments > a';
|
||||
this.waitForSelector(selector);
|
||||
this.thenClick(selector);
|
||||
|
||||
// append a new cell
|
||||
this.append_cell('', 'markdown');
|
||||
this.thenEvaluate(function() {
|
||||
Jupyter.notebook.select_next();
|
||||
});
|
||||
|
||||
// and paste the attachments into it
|
||||
selector = '#paste_cell_attachments > a';
|
||||
this.waitForSelector(selector);
|
||||
this.thenClick(selector);
|
||||
|
||||
// check that the new cell has attachments
|
||||
this.then(function() {
|
||||
var cell_attachments = this.evaluate(function() {
|
||||
return Jupyter.notebook.get_selected_cell().attachments;
|
||||
});
|
||||
var orig_cell_attachments = this.evaluate(function() {
|
||||
return Jupyter.notebook.get_cell(0).attachments;
|
||||
});
|
||||
// Check that the two cells have the same attachments
|
||||
this.test.assertEquals(cell_attachments, orig_cell_attachments,
|
||||
"pasted attachments ok");
|
||||
});
|
||||
|
||||
// copy/paste cell includes attachments
|
||||
selector = '#copy_cell > a';
|
||||
this.waitForSelector(selector);
|
||||
this.thenClick(selector);
|
||||
|
||||
selector = '#paste_cell_below > a';
|
||||
this.waitForSelector(selector);
|
||||
this.thenClick(selector);
|
||||
|
||||
// check that the new cell has attachments
|
||||
this.then(function() {
|
||||
var cell_attachments = this.evaluate(function() {
|
||||
return Jupyter.notebook.get_selected_cell().attachments;
|
||||
});
|
||||
var orig_cell_attachments = this.evaluate(function() {
|
||||
return Jupyter.notebook.get_cell(0).attachments;
|
||||
});
|
||||
// Check that the two cells have the same attachments
|
||||
this.test.assertEquals(cell_attachments, orig_cell_attachments,
|
||||
"pasted cell has attachments");
|
||||
});
|
||||
|
||||
var nbname = 'attachments_test.ipynb';
|
||||
this.thenEvaluate(function(nbname) {
|
||||
Jupyter.notebook.set_notebook_name(nbname);
|
||||
}, {nbname:nbname});
|
||||
|
||||
// -- Save the notebook. This should cause garbage collection for the
|
||||
// second cell (since we just pasted the attachments but there is no
|
||||
// markdown referencing them)
|
||||
this.thenEvaluate(function(nbname) {
|
||||
Jupyter._checkpoint_created = false;
|
||||
require(['base/js/events'], function (events) {
|
||||
events.on('checkpoint_created.Notebook', function (evt, data) {
|
||||
Jupyter._checkpoint_created = true;
|
||||
});
|
||||
});
|
||||
|
||||
Jupyter.notebook.save_checkpoint();
|
||||
}, {nbname:nbname});
|
||||
|
||||
this.waitFor(function () {
|
||||
return this.evaluate(function(){
|
||||
return Jupyter._checkpoint_created;
|
||||
});
|
||||
});
|
||||
|
||||
this.then(function(){
|
||||
this.open_dashboard();
|
||||
});
|
||||
|
||||
|
||||
this.then(function(){
|
||||
var notebook_url = this.evaluate(function(nbname){
|
||||
var escaped_name = encodeURIComponent(nbname);
|
||||
var return_this_thing = null;
|
||||
$("a.item_link").map(function (i,a) {
|
||||
if (a.href.indexOf(escaped_name) >= 0) {
|
||||
return_this_thing = a.href;
|
||||
return;
|
||||
}
|
||||
});
|
||||
return return_this_thing;
|
||||
}, {nbname:nbname});
|
||||
this.test.assertNotEquals(notebook_url, null, "Escaped URL in notebook list");
|
||||
// open the notebook
|
||||
this.open(notebook_url);
|
||||
});
|
||||
|
||||
// wait for the notebook
|
||||
this.waitFor(this.kernel_running);
|
||||
this.waitFor(function() {
|
||||
return this.evaluate(function () {
|
||||
return Jupyter && Jupyter.notebook && true;
|
||||
});
|
||||
});
|
||||
|
||||
this.then(function() {
|
||||
var cell0 = this.evaluate(function() {
|
||||
return Jupyter.notebook.get_cell(0);
|
||||
});
|
||||
var cell1 = this.evaluate(function() {
|
||||
return Jupyter.notebook.get_cell(1);
|
||||
});
|
||||
this.test.assert('black_square_22.png' in cell0.attachments,
|
||||
'cell0 has kept its attachments');
|
||||
this.test.assertEquals(Object.keys(cell1.attachments).length, 0,
|
||||
'cell1 attachments have been garbage collected');
|
||||
});
|
||||
});
|
||||
|
192
venv/Lib/site-packages/notebook/tests/notebook/display_id.js
Normal file
192
venv/Lib/site-packages/notebook/tests/notebook/display_id.js
Normal file
|
@ -0,0 +1,192 @@
|
|||
//
|
||||
// Various output tests
|
||||
//
|
||||
|
||||
casper.notebook_test(function () {
|
||||
|
||||
function get_outputs(cell_idx) {
|
||||
var outputs_json = casper.evaluate(function (cell_idx) {
|
||||
var cell = Jupyter.notebook.get_cell(cell_idx);
|
||||
return JSON.stringify(cell.output_area.outputs);
|
||||
}, {cell_idx: cell_idx});
|
||||
return JSON.parse(outputs_json);
|
||||
}
|
||||
|
||||
this.thenEvaluate(function () {
|
||||
Jupyter.notebook.insert_cell_at_index("code", 0);
|
||||
var cell = Jupyter.notebook.get_cell(0);
|
||||
cell.set_text([
|
||||
"ip = get_ipython()",
|
||||
"from IPython.display import display",
|
||||
"def display_with_id(obj, display_id, update=False, execute_result=False):",
|
||||
" iopub = ip.kernel.iopub_socket",
|
||||
" session = get_ipython().kernel.session",
|
||||
" data, md = ip.display_formatter.format(obj)",
|
||||
" transient = {'display_id': display_id}",
|
||||
" content = {'data': data, 'metadata': md, 'transient': transient}",
|
||||
" if execute_result:",
|
||||
" msg_type = 'execute_result'",
|
||||
" content['execution_count'] = ip.execution_count",
|
||||
" else:",
|
||||
" msg_type = 'update_display_data' if update else 'display_data'",
|
||||
" session.send(iopub, msg_type, content, parent=ip.parent_header)",
|
||||
"",
|
||||
].join('\n'));
|
||||
cell.execute();
|
||||
});
|
||||
|
||||
this.thenEvaluate(function () {
|
||||
Jupyter.notebook.insert_cell_at_index("code", 1);
|
||||
var cell = Jupyter.notebook.get_cell(1);
|
||||
cell.set_text([
|
||||
"display('above')",
|
||||
"display_with_id(1, 'here')",
|
||||
"display('below')",
|
||||
].join('\n'));
|
||||
cell.execute();
|
||||
});
|
||||
|
||||
this.wait_for_output(1);
|
||||
this.wait_for_idle()
|
||||
|
||||
this.then(function () {
|
||||
var outputs = get_outputs(1);
|
||||
this.test.assertEquals(outputs.length, 3, 'cell 1 has the right number of outputs');
|
||||
this.test.assertEquals(outputs[1].transient.display_id, 'here', 'has transient display_id');
|
||||
this.test.assertEquals(outputs[1].data['text/plain'], '1', 'display_with_id produces output');
|
||||
});
|
||||
|
||||
|
||||
this.thenEvaluate(function () {
|
||||
Jupyter.notebook.insert_cell_at_index("code", 2);
|
||||
var cell = Jupyter.notebook.get_cell(2);
|
||||
cell.set_text([
|
||||
"display_with_id(2, 'here')",
|
||||
"display_with_id(3, 'there')",
|
||||
"display_with_id(4, 'here')",
|
||||
].join('\n'));
|
||||
cell.execute();
|
||||
});
|
||||
|
||||
this.wait_for_output(2);
|
||||
this.wait_for_idle();
|
||||
|
||||
this.then(function () {
|
||||
var outputs1 = get_outputs(1);
|
||||
this.test.assertEquals(outputs1[1].data['text/plain'], '4', '');
|
||||
this.test.assertEquals(outputs1.length, 3, 'cell 1 still has the right number of outputs');
|
||||
var outputs2 = get_outputs(2);
|
||||
this.test.assertEquals(outputs2.length, 3, 'cell 2 has the right number of outputs');
|
||||
this.test.assertEquals(outputs2[0].transient.display_id, 'here', 'check display id 0');
|
||||
this.test.assertEquals(outputs2[0].data['text/plain'], '4', 'output[2][0]');
|
||||
this.test.assertEquals(outputs2[1].transient.display_id, 'there', 'display id 1');
|
||||
this.test.assertEquals(outputs2[1].data['text/plain'], '3', 'output[2][1]');
|
||||
this.test.assertEquals(outputs2[2].transient.display_id, 'here', 'display id 2');
|
||||
this.test.assertEquals(outputs2[2].data['text/plain'], '4', 'output[2][2]');
|
||||
});
|
||||
|
||||
this.then(function () {
|
||||
this.echo("Test output callback overrides work with display ids");
|
||||
});
|
||||
|
||||
this.thenEvaluate(function () {
|
||||
Jupyter.notebook.insert_cell_at_index("code", 3);
|
||||
var cell = Jupyter.notebook.get_cell(3);
|
||||
cell.set_text([
|
||||
"display_with_id(5, 'here')",
|
||||
"display_with_id(6, 'here', update=True)",
|
||||
].join('\n'));
|
||||
cell.execute();
|
||||
var kernel = IPython.notebook.kernel;
|
||||
var msg_id = cell.last_msg_id;
|
||||
var callback_id = 'mycallbackid'
|
||||
cell.iopub_messages = [];
|
||||
var add_msg = function(msg) {
|
||||
msg.content.output_type = msg.msg_type;
|
||||
cell.iopub_messages.push(msg.content);
|
||||
};
|
||||
kernel.set_callbacks_for_msg(callback_id, {
|
||||
iopub: {
|
||||
output: add_msg,
|
||||
clear_output: add_msg,
|
||||
}
|
||||
}, false);
|
||||
kernel.output_callback_overrides_push(msg_id, callback_id);
|
||||
});
|
||||
|
||||
this.waitFor(function () {
|
||||
return this.evaluate(function () {
|
||||
var cell = IPython.notebook.get_cell(3);
|
||||
return cell.iopub_messages.length >= 2;
|
||||
});
|
||||
});
|
||||
this.wait_for_idle();
|
||||
|
||||
this.then(function () {
|
||||
var returned = this.evaluate(function () {
|
||||
var cell = IPython.notebook.get_cell(3);
|
||||
return [cell.output_area.outputs, cell.iopub_messages];
|
||||
});
|
||||
var cell_results = returned[0];
|
||||
var callback_results = returned[1];
|
||||
this.test.assertEquals(cell_results.length, 0, "correct number of cell outputs");
|
||||
this.test.assertEquals(callback_results.length, 2, "correct number of callback outputs");
|
||||
this.test.assertEquals(callback_results[0].output_type, 'display_data', 'check output_type 0');
|
||||
this.test.assertEquals(callback_results[0].transient.display_id, 'here', 'check display id 0');
|
||||
this.test.assertEquals(callback_results[0].data['text/plain'], '5', 'value');
|
||||
this.test.assertEquals(callback_results[1].output_type, 'update_display_data', 'check output_type 1');
|
||||
this.test.assertEquals(callback_results[1].transient.display_id, 'here', 'display id 1');
|
||||
this.test.assertEquals(callback_results[1].data['text/plain'], '6', 'value');
|
||||
});
|
||||
|
||||
this.thenEvaluate(function () {
|
||||
Jupyter.notebook.insert_cell_at_index("code", 4);
|
||||
var cell = Jupyter.notebook.get_cell(4);
|
||||
cell.set_text([
|
||||
"display_with_id(7, 'here')",
|
||||
"display_with_id(8, 'here', update=True)",
|
||||
"display_with_id(9, 'result', execute_result=True)"
|
||||
].join('\n'));
|
||||
cell.execute();
|
||||
|
||||
Jupyter.notebook.insert_cell_at_index("code", 5);
|
||||
var cell = Jupyter.notebook.get_cell(5);
|
||||
cell.set_text([
|
||||
"display_with_id(10, 'result', update=True)",
|
||||
"1",
|
||||
].join('\n'));
|
||||
cell.execute();
|
||||
});
|
||||
|
||||
this.wait_for_output(4);
|
||||
this.wait_for_output(5);
|
||||
this.wait_for_idle();
|
||||
|
||||
this.then(function () {
|
||||
var returned = JSON.parse(this.evaluate(function () {
|
||||
var cell3 = Jupyter.notebook.get_cell(3);
|
||||
var cell4 = Jupyter.notebook.get_cell(4);
|
||||
return JSON.stringify([cell4.output_area.outputs, cell3.iopub_messages]);
|
||||
}));
|
||||
var cell_results = returned[0];
|
||||
var callback_results = returned[1];
|
||||
this.test.assertEquals(cell_results.length, 2, "correct number of cell outputs");
|
||||
this.test.assertEquals(callback_results.length, 4, "correct number of callback outputs");
|
||||
this.test.assertEquals(callback_results[0].output_type, 'display_data', 'check output_type 0');
|
||||
this.test.assertEquals(callback_results[0].transient.display_id, 'here', 'check display id 0');
|
||||
this.test.assertEquals(callback_results[0].data['text/plain'], '5', 'value');
|
||||
this.test.assertEquals(callback_results[1].output_type, 'update_display_data', 'check output_type 1');
|
||||
this.test.assertEquals(callback_results[1].transient.display_id, 'here', 'display id 1');
|
||||
this.test.assertEquals(callback_results[1].data['text/plain'], '6', 'value');
|
||||
this.test.assertEquals(callback_results[2].output_type, 'display_data', 'check output_type 2');
|
||||
this.test.assertEquals(callback_results[2].transient.display_id, 'here', 'check display id 2');
|
||||
this.test.assertEquals(callback_results[2].data['text/plain'], '7', 'value');
|
||||
this.test.assertEquals(callback_results[3].output_type, 'update_display_data', 'check output_type 3');
|
||||
this.test.assertEquals(callback_results[3].transient.display_id, 'here', 'display id 3');
|
||||
this.test.assertEquals(callback_results[3].data['text/plain'], '8', 'value');
|
||||
|
||||
this.test.assertEquals(cell_results[1].data['text/plain'], '10', 'update execute_result')
|
||||
});
|
||||
|
||||
|
||||
});
|
116
venv/Lib/site-packages/notebook/tests/notebook/dualmode.js
Normal file
116
venv/Lib/site-packages/notebook/tests/notebook/dualmode.js
Normal file
|
@ -0,0 +1,116 @@
|
|||
// Test the notebook dual mode feature.
|
||||
|
||||
// Test
|
||||
casper.notebook_test(function () {
|
||||
var a = 'print("a")';
|
||||
var index = this.append_cell(a);
|
||||
this.execute_cell_then(index);
|
||||
|
||||
var b = 'print("b")';
|
||||
index = this.append_cell(b);
|
||||
this.execute_cell_then(index);
|
||||
|
||||
var c = 'print("c")';
|
||||
index = this.append_cell(c);
|
||||
this.execute_cell_then(index);
|
||||
|
||||
this.then(function () {
|
||||
if (this.slimerjs) {
|
||||
// When running in xvfb, the Slimer window doesn't always have focus
|
||||
// immediately. By clicking on a new element on the page we can force
|
||||
// it to gain focus.
|
||||
this.click_cell_editor(1);
|
||||
this.click_cell_editor(0);
|
||||
}
|
||||
|
||||
this.validate_notebook_state('initial state', 'edit', 0);
|
||||
this.trigger_keydown('esc');
|
||||
this.validate_notebook_state('esc', 'command', 0);
|
||||
this.trigger_keydown('down');
|
||||
this.validate_notebook_state('down', 'command', 1);
|
||||
this.trigger_keydown('enter');
|
||||
this.validate_notebook_state('enter', 'edit', 1);
|
||||
this.trigger_keydown('j');
|
||||
this.validate_notebook_state('j in edit mode', 'edit', 1);
|
||||
this.trigger_keydown('esc');
|
||||
this.validate_notebook_state('esc', 'command', 1);
|
||||
this.trigger_keydown('j');
|
||||
this.validate_notebook_state('j in command mode', 'command', 2);
|
||||
this.click_cell_editor(0);
|
||||
this.validate_notebook_state('click cell 0', 'edit', 0);
|
||||
this.click_cell_editor(3);
|
||||
this.validate_notebook_state('click cell 3', 'edit', 3);
|
||||
this.trigger_keydown('esc');
|
||||
this.validate_notebook_state('esc', 'command', 3);
|
||||
|
||||
// Open keyboard help
|
||||
this.evaluate(function(){
|
||||
$('#keyboard_shortcuts a').click();
|
||||
}, {});
|
||||
});
|
||||
|
||||
// Wait for the dialog to fade in completely.
|
||||
this.waitForSelector('div.modal', function() {
|
||||
this.evaluate(function(){
|
||||
IPython.modal_shown = false;
|
||||
$('div.modal').on('shown.bs.modal', function (){
|
||||
IPython.modal_shown = true;
|
||||
});
|
||||
$('div.modal').on('hidden.bs.modal', function (){
|
||||
IPython.modal_shown = false;
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
this.waitFor(function () {
|
||||
return this.evaluate(function(){
|
||||
return IPython.modal_shown;
|
||||
});
|
||||
},
|
||||
function() {
|
||||
this.trigger_keydown('k');
|
||||
this.validate_notebook_state('k in command mode while keyboard help is up', 'command', 3);
|
||||
|
||||
// Close keyboard help
|
||||
this.evaluate(function(){
|
||||
$('div.modal-footer button.btn-default').click();
|
||||
}, {});
|
||||
});
|
||||
|
||||
// Wait for the dialog to fade out completely.
|
||||
this.waitFor(function () {
|
||||
return this.evaluate(function(){
|
||||
return !IPython.modal_shown;
|
||||
});
|
||||
},
|
||||
function() {
|
||||
|
||||
this.trigger_keydown('k');
|
||||
this.validate_notebook_state('k in command mode', 'command', 2);
|
||||
this.click_cell_editor(0);
|
||||
this.validate_notebook_state('click cell 0', 'edit', 0);
|
||||
this.focus_notebook();
|
||||
this.validate_notebook_state('focus #notebook', 'command', 0);
|
||||
this.click_cell_editor(0);
|
||||
this.validate_notebook_state('click cell 0', 'edit', 0);
|
||||
this.focus_notebook();
|
||||
this.validate_notebook_state('focus #notebook', 'command', 0);
|
||||
this.click_cell_editor(3);
|
||||
this.validate_notebook_state('click cell 3', 'edit', 3);
|
||||
|
||||
// Cell deletion
|
||||
this.trigger_keydown('esc', 'd', 'd');
|
||||
this.test.assertEquals(this.get_cells_length(), 3, 'dd actually deletes a cell');
|
||||
this.validate_notebook_state('dd', 'command', 2);
|
||||
|
||||
// Make sure that if the time between d presses is too long, nothing gets removed.
|
||||
this.trigger_keydown('d');
|
||||
});
|
||||
this.wait(1000);
|
||||
this.then(function () {
|
||||
this.trigger_keydown('d');
|
||||
this.test.assertEquals(this.get_cells_length(), 3, "d, 1 second wait, d doesn't delete a cell");
|
||||
this.validate_notebook_state('d, 1 second wait, d', 'command', 2);
|
||||
});
|
||||
});
|
198
venv/Lib/site-packages/notebook/tests/notebook/dualmode_merge.js
Normal file
198
venv/Lib/site-packages/notebook/tests/notebook/dualmode_merge.js
Normal file
|
@ -0,0 +1,198 @@
|
|||
|
||||
// Test
|
||||
casper.notebook_test(function () {
|
||||
var a = 'ab\n\ncd';
|
||||
var b = 'print("b")';
|
||||
var c = 'print("c")';
|
||||
var d = '"d"';
|
||||
var e = '"e"';
|
||||
var f = '"f"';
|
||||
var g = '"g"';
|
||||
var N = 7;
|
||||
|
||||
var that = this;
|
||||
var cell_is_mergeable = function (index) {
|
||||
// Get the mergeable status of a cell.
|
||||
return that.evaluate(function (index) {
|
||||
var cell = IPython.notebook.get_cell(index);
|
||||
return cell.is_mergeable();
|
||||
}, index);
|
||||
};
|
||||
|
||||
var cell_is_splittable = function (index) {
|
||||
// Get the splittable status of a cell.
|
||||
return that.evaluate(function (index) {
|
||||
var cell = IPython.notebook.get_cell(index);
|
||||
return cell.is_splittable();
|
||||
}, index);
|
||||
};
|
||||
|
||||
var close_dialog = function () {
|
||||
this.evaluate(function(){
|
||||
$('div.modal-footer button.btn-default').click();
|
||||
}, {});
|
||||
};
|
||||
|
||||
this.then(function () {
|
||||
// Split and merge cells
|
||||
this.select_cell(0);
|
||||
this.trigger_keydown('a', 'enter'); // Create cell above and enter edit mode.
|
||||
this.validate_notebook_state('a, enter', 'edit', 0);
|
||||
this.set_cell_text(0, 'abcd');
|
||||
this.set_cell_editor_cursor(0, 0, 2);
|
||||
this.test.assertEquals(this.get_cell_text(0), 'abcd', 'Verify that cell 0 has the new contents.');
|
||||
this.trigger_keydown('ctrl-shift--'); // Split
|
||||
this.test.assertEquals(this.get_cell_text(0), 'ab', 'split; Verify that cell 0 has the first half.');
|
||||
this.test.assertEquals(this.get_cell_text(1), 'cd', 'split; Verify that cell 1 has the second half.');
|
||||
this.validate_notebook_state('split', 'edit', 1);
|
||||
this.select_cell(0); // Move up to cell 0
|
||||
this.evaluate(function() { IPython.notebook.extend_selection_by(1);});
|
||||
this.trigger_keydown('shift-m'); // Merge
|
||||
this.validate_notebook_state('merge', 'command', 0);
|
||||
this.test.assertEquals(this.get_cell_text(0), a, 'merge; Verify that cell 0 has the merged contents.');
|
||||
});
|
||||
|
||||
// add some more cells and test splitting/merging when a cell is not deletable
|
||||
this.then(function () {
|
||||
this.append_cell(b);
|
||||
this.append_cell(c);
|
||||
this.append_cell(d);
|
||||
this.append_cell(e);
|
||||
this.append_cell(f);
|
||||
this.append_cell(g);
|
||||
});
|
||||
|
||||
this.thenEvaluate(function() {
|
||||
IPython.notebook.get_cell(1).metadata.deletable = false;
|
||||
});
|
||||
|
||||
// Check that merge/split status are correct
|
||||
this.then(function () {
|
||||
this.test.assert(cell_is_splittable(0), 'Cell 0 is splittable');
|
||||
this.test.assert(cell_is_mergeable(0), 'Cell 0 is mergeable');
|
||||
this.test.assert(!cell_is_splittable(1), 'Cell 1 is not splittable');
|
||||
this.test.assert(!cell_is_mergeable(1), 'Cell 1 is not mergeable');
|
||||
this.test.assert(cell_is_splittable(2), 'Cell 2 is splittable');
|
||||
this.test.assert(cell_is_mergeable(2), 'Cell 2 is mergeable');
|
||||
});
|
||||
|
||||
// Try to merge cell 0 above, nothing should happen
|
||||
this.then(function () {
|
||||
this.select_cell(0);
|
||||
});
|
||||
this.thenEvaluate(function() {
|
||||
IPython.notebook.merge_cell_above();
|
||||
});
|
||||
this.then(function() {
|
||||
this.test.assertEquals(this.get_cells_length(), N, 'Merge cell 0 above: There are still '+N+' cells');
|
||||
this.test.assertEquals(this.get_cell_text(0), a, 'Merge cell 0 above: Cell 0 is unchanged');
|
||||
this.test.assertEquals(this.get_cell_text(1), b, 'Merge cell 0 above: Cell 1 is unchanged');
|
||||
this.test.assertEquals(this.get_cell_text(2), c, 'Merge cell 0 above: Cell 2 is unchanged');
|
||||
this.validate_notebook_state('merge up', 'command', 0);
|
||||
});
|
||||
|
||||
// Try to merge cell 0 below with cell 1, should not work, as 1 is locked
|
||||
this.then(function () {
|
||||
this.trigger_keydown('esc');
|
||||
this.select_cell(0);
|
||||
this.select_cell(1,false);
|
||||
this.trigger_keydown('shift-m');
|
||||
this.trigger_keydown('esc');
|
||||
this.test.assertEquals(this.get_cells_length(), N, 'Merge cell 0 down: There are still '+N+' cells');
|
||||
this.test.assertEquals(this.get_cell_text(0), a, 'Merge cell 0 down: Cell 0 is unchanged');
|
||||
this.test.assertEquals(this.get_cell_text(1), b, 'Merge cell 0 down: Cell 1 is unchanged');
|
||||
this.test.assertEquals(this.get_cell_text(2), c, 'Merge cell 0 down: Cell 2 is unchanged');
|
||||
this.validate_notebook_state('merge 0 with 1', 'command', 1);
|
||||
});
|
||||
|
||||
// Try to merge cell 1 above with cell 0
|
||||
this.then(function () {
|
||||
this.select_cell(1);
|
||||
});
|
||||
this.thenEvaluate(function () {
|
||||
IPython.notebook.merge_cell_above();
|
||||
});
|
||||
this.then(function () {
|
||||
this.test.assertEquals(this.get_cells_length(), N, 'Merge cell 1 up: There are still '+N+' cells');
|
||||
this.test.assertEquals(this.get_cell_text(0), a, 'Merge cell 1 up: Cell 0 is unchanged');
|
||||
this.test.assertEquals(this.get_cell_text(1), b, 'Merge cell 1 up: Cell 1 is unchanged');
|
||||
this.test.assertEquals(this.get_cell_text(2), c, 'Merge cell 1 up: Cell 2 is unchanged');
|
||||
this.validate_notebook_state('merge up', 'command', 1);
|
||||
});
|
||||
|
||||
// Try to split cell 1
|
||||
this.then(function () {
|
||||
this.select_cell(1);
|
||||
this.trigger_keydown('enter');
|
||||
this.set_cell_editor_cursor(1, 0, 2);
|
||||
this.trigger_keydown('ctrl-shift--'); // Split
|
||||
this.test.assertEquals(this.get_cells_length(), N, 'Split cell 1: There are still '+N+' cells');
|
||||
this.test.assertEquals(this.get_cell_text(0), a, 'Split cell 1: Cell 0 is unchanged');
|
||||
this.test.assertEquals(this.get_cell_text(1), b, 'Split cell 1: Cell 1 is unchanged');
|
||||
this.test.assertEquals(this.get_cell_text(2), c, 'Split cell 1: Cell 2 is unchanged');
|
||||
this.validate_notebook_state('ctrl-shift--', 'edit', 1);
|
||||
});
|
||||
|
||||
// Try to merge cell 1 down, should fail, as 1 is locked
|
||||
this.then(function () {
|
||||
this.trigger_keydown('esc');
|
||||
this.select_cell(1);
|
||||
this.select_cell(2, false); // extend selection
|
||||
this.trigger_keydown('shift-m');
|
||||
this.trigger_keydown('esc');
|
||||
this.test.assertEquals(this.get_cells_length(), N, 'Merge cell 1 down: There are still '+N+' cells');
|
||||
this.test.assertEquals(this.get_cell_text(0), a, 'Merge cell 1 down: Cell 0 is unchanged');
|
||||
this.test.assertEquals(this.get_cell_text(1), b, 'Merge cell 1 down: Cell 1 is unchanged');
|
||||
this.test.assertEquals(this.get_cell_text(2), c, 'Merge cell 1 down: Cell 2 is unchanged');
|
||||
this.validate_notebook_state('Merge 1 with 2', 'command', 2);
|
||||
});
|
||||
|
||||
// Try to merge cell 2 above with cell 1, should fail, 1 is locked
|
||||
this.then(function () {
|
||||
this.select_cell(2);
|
||||
});
|
||||
this.thenEvaluate(function () {
|
||||
IPython.notebook.merge_cell_above();
|
||||
});
|
||||
this.then(function () {
|
||||
this.test.assertEquals(this.get_cells_length(), N, 'Merge cell 2 up: There are still '+N+' cells');
|
||||
this.test.assertEquals(this.get_cell_text(0), a, 'Merge cell 2 up: Cell 0 is unchanged');
|
||||
this.test.assertEquals(this.get_cell_text(1), b, 'Merge cell 2 up: Cell 1 is unchanged');
|
||||
this.test.assertEquals(this.get_cell_text(2), c, 'Merge cell 2 up: Cell 2 is unchanged');
|
||||
this.validate_notebook_state('merge up', 'command', 2);
|
||||
});
|
||||
|
||||
this.then(function () {
|
||||
this.trigger_keydown('esc');
|
||||
this.select_cell(3);
|
||||
this.select_cell(4, false); // extend selection
|
||||
this.trigger_keydown('shift-m');
|
||||
this.trigger_keydown('esc');
|
||||
this.test.assertEquals(this.get_cells_length(), N-1 , 'Merge cell 3 with 4: There are now '+(N-1)+' cells');
|
||||
this.test.assertEquals(this.get_cell_text(0), a, 'Merge cell 3 with 4: Cell 0 is unchanged');
|
||||
this.test.assertEquals(this.get_cell_text(1), b, 'Merge cell 3 with 4: Cell 1 is unchanged');
|
||||
this.test.assertEquals(this.get_cell_text(2), c, 'Merge cell 3 with 4: Cell 2 is unchanged');
|
||||
this.test.assertEquals(this.get_cell_text(3), d+'\n\n'+e, 'Merge cell 3 with 4: Cell 3 is merged');
|
||||
this.test.assertEquals(this.get_cell_text(4), f, 'Merge cell 3 with 4: Cell 5 is now cell 4');
|
||||
this.test.assertEquals(this.get_cell_text(5), g, 'Merge cell 3 with 4: Cell 6 is now cell 5');
|
||||
this.validate_notebook_state('actual merge', 'command', 3);
|
||||
});
|
||||
|
||||
|
||||
this.then(function () {
|
||||
this.trigger_keydown('esc');
|
||||
this.select_cell(4);
|
||||
// shift-m on single selection does nothing.
|
||||
this.trigger_keydown('shift-m');
|
||||
this.trigger_keydown('esc');
|
||||
this.test.assertEquals(this.get_cells_length(), N-2 , 'Merge cell 4 with 5: There are now '+(N-2)+' cells');
|
||||
this.test.assertEquals(this.get_cell_text(0), a, 'Merge cell 4 with 5: Cell 0 is unchanged');
|
||||
this.test.assertEquals(this.get_cell_text(1), b, 'Merge cell 4 with 5: Cell 1 is unchanged');
|
||||
this.test.assertEquals(this.get_cell_text(2), c, 'Merge cell 4 with 5: Cell 2 is unchanged');
|
||||
this.test.assertEquals(this.get_cell_text(3), d+'\n\n'+e, 'Merge cell 4 with 5: Cell 3 is unchanged');
|
||||
this.test.assertEquals(this.get_cell_text(4), f+'\n\n'+g, 'Merge cell 4 with 5: Cell 4 and 5 are merged');
|
||||
this.validate_notebook_state('merge on single cell merge with below', 'command', 4);
|
||||
});
|
||||
|
||||
|
||||
});
|
|
@ -0,0 +1,178 @@
|
|||
//
|
||||
// Test that the correct cells are executed when there are marked cells.
|
||||
//
|
||||
casper.notebook_test(function () {
|
||||
var that = this;
|
||||
var assert_outputs = function (expected, msg_prefix) {
|
||||
var msg, i;
|
||||
msg_prefix = "(assert_outputs) "+(msg_prefix || 'no prefix')+": ";
|
||||
for (i = 0; i < that.get_cells_length(); i++) {
|
||||
if (expected[i] === undefined) {
|
||||
msg = msg_prefix + 'cell ' + i + ' not executed';
|
||||
that.test.assertFalse(that.cell_has_outputs(i), msg);
|
||||
|
||||
} else {
|
||||
msg = msg_prefix + 'cell ' + i + ' executed';
|
||||
var out = (that.get_output_cell(i, undefined, msg_prefix)||{test:'<no cells>'}).text
|
||||
that.test.assertEquals(out, expected[i], msg + ', out is: '+out);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
this.then(function () {
|
||||
this.set_cell_text(0, 'print("a")');
|
||||
this.append_cell('print("b")');
|
||||
this.append_cell('print("c")');
|
||||
this.append_cell('print("d")');
|
||||
this.test.assertEquals(this.get_cells_length(), 4, "correct number of cells");
|
||||
});
|
||||
|
||||
this.then(function () {
|
||||
this.select_cell(1);
|
||||
this.select_cell(2, false);
|
||||
});
|
||||
|
||||
this.then(function () {
|
||||
this.evaluate(function () {
|
||||
IPython.notebook.clear_all_output();
|
||||
});
|
||||
})
|
||||
|
||||
this.then(function(){
|
||||
this.select_cell(1);
|
||||
this.validate_notebook_state('before execute 1', 'command', 1);
|
||||
this.select_cell(1);
|
||||
this.select_cell(2, false);
|
||||
this.trigger_keydown('ctrl-enter');
|
||||
});
|
||||
|
||||
this.wait_for_output(1);
|
||||
this.wait_for_output(2);
|
||||
|
||||
this.then(function () {
|
||||
assert_outputs([undefined, 'b\n', 'c\n', undefined], 'run selected 1');
|
||||
this.validate_notebook_state('run selected cells 1', 'command', 2);
|
||||
});
|
||||
|
||||
|
||||
// execute and insert below when there are selected cells
|
||||
this.then(function () {
|
||||
this.evaluate(function () {
|
||||
IPython.notebook.clear_all_output();
|
||||
});
|
||||
|
||||
this.select_cell(1);
|
||||
this.validate_notebook_state('before execute 2', 'command', 1);
|
||||
this.evaluate(function () {
|
||||
$("#run_cell_insert_below").click();
|
||||
});
|
||||
});
|
||||
|
||||
this.wait_for_output(1);
|
||||
|
||||
this.then(function () {
|
||||
assert_outputs([undefined, 'b\n', undefined, undefined , undefined],'run selected cells 2');
|
||||
this.validate_notebook_state('run selected cells 2', 'edit', 2);
|
||||
});
|
||||
|
||||
// check that it doesn't affect run all above
|
||||
this.then(function () {
|
||||
this.evaluate(function () {
|
||||
IPython.notebook.clear_all_output();
|
||||
});
|
||||
|
||||
this.select_cell(1);
|
||||
this.validate_notebook_state('before execute 3', 'command', 1);
|
||||
this.evaluate(function () {
|
||||
$("#run_all_cells_above").click();
|
||||
});
|
||||
});
|
||||
|
||||
this.wait_for_output(0);
|
||||
|
||||
this.then(function () {
|
||||
assert_outputs(['a\n', undefined, undefined, undefined],'run cells above');
|
||||
this.validate_notebook_state('run cells above', 'command', 0);
|
||||
});
|
||||
|
||||
// check that it doesn't affect run all below
|
||||
this.then(function () {
|
||||
this.evaluate(function () {
|
||||
IPython.notebook.clear_all_output();
|
||||
});
|
||||
|
||||
this.select_cell(1);
|
||||
this.validate_notebook_state('before execute 4', 'command', 1);
|
||||
this.evaluate(function () {
|
||||
$("#run_all_cells_below").click();
|
||||
});
|
||||
});
|
||||
|
||||
this.wait_for_output(1);
|
||||
this.wait_for_output(2);
|
||||
this.wait_for_output(3);
|
||||
|
||||
this.then(function () {
|
||||
assert_outputs([undefined, 'b\n', undefined, 'c\n', 'd\n'],'run cells below');
|
||||
this.validate_notebook_state('run cells below', 'command', 4);
|
||||
});
|
||||
|
||||
// check that it doesn't affect run all
|
||||
this.then(function () {
|
||||
this.evaluate(function () {
|
||||
IPython.notebook.clear_all_output();
|
||||
});
|
||||
|
||||
this.select_cell(1);
|
||||
this.validate_notebook_state('before execute 5', 'command', 1);
|
||||
this.evaluate(function () {
|
||||
$("#run_all_cells").click();
|
||||
});
|
||||
});
|
||||
|
||||
this.wait_for_output(0);
|
||||
this.wait_for_output(1);
|
||||
this.wait_for_output(2);
|
||||
this.wait_for_output(3);
|
||||
|
||||
this.then(function () {
|
||||
assert_outputs(['a\n', 'b\n', undefined, 'c\n', 'd\n'],'run all cells');
|
||||
this.validate_notebook_state('run all cells', 'command', 4);
|
||||
});
|
||||
|
||||
this.then(function(){
|
||||
this.set_cell_text(0, 'print("x")');
|
||||
this.set_cell_text(1, 'print("y")');
|
||||
|
||||
this.select_cell(0);
|
||||
this.select_cell(1, false);
|
||||
this.trigger_keydown('alt-enter');
|
||||
|
||||
});
|
||||
|
||||
this.wait_for_output(0);
|
||||
this.wait_for_output(1);
|
||||
this.then(function () {
|
||||
assert_outputs(['x\n', 'y\n', undefined, undefined, 'c\n', 'd\n'],'run selection and insert below');
|
||||
this.validate_notebook_state('run selection insert below', 'edit', 2);
|
||||
});
|
||||
|
||||
this.then(function(){
|
||||
this.set_cell_text(1, 'print("z")');
|
||||
this.set_cell_text(2, 'print("a")');
|
||||
|
||||
this.select_cell(1);
|
||||
this.select_cell(2, false);
|
||||
this.evaluate(function () {
|
||||
$("#run_cell_select_below").click();
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
this.wait_for_output(1);
|
||||
this.wait_for_output(2);
|
||||
this.then(function () {
|
||||
assert_outputs(['x\n', 'z\n', 'a\n', undefined, 'c\n', 'd\n'],'run selection and select below');
|
||||
this.validate_notebook_state('run selection select below', 'command', 3);
|
||||
});
|
||||
});
|
23
venv/Lib/site-packages/notebook/tests/notebook/inject_js.js
Normal file
23
venv/Lib/site-packages/notebook/tests/notebook/inject_js.js
Normal file
|
@ -0,0 +1,23 @@
|
|||
//
|
||||
// Test robustness about JS injection in different place
|
||||
//
|
||||
// This assume malicious document arrive to the frontend.
|
||||
//
|
||||
|
||||
casper.notebook_test(function () {
|
||||
var messages = [];
|
||||
this.on('remote.alert', function (msg) {
|
||||
messages.push(msg);
|
||||
});
|
||||
|
||||
this.evaluate(function () {
|
||||
var cell = IPython.notebook.get_cell(0);
|
||||
var json = cell.toJSON();
|
||||
json.execution_count = "<script> alert('hello from input prompts !')</script>";
|
||||
cell.fromJSON(json);
|
||||
});
|
||||
|
||||
this.then(function () {
|
||||
this.test.assert(messages.length == 0, "Captured log message from script tag injection !");
|
||||
});
|
||||
});
|
64
venv/Lib/site-packages/notebook/tests/notebook/markdown.js
Normal file
64
venv/Lib/site-packages/notebook/tests/notebook/markdown.js
Normal file
|
@ -0,0 +1,64 @@
|
|||
//
|
||||
// Test that a Markdown cell is rendered to HTML.
|
||||
//
|
||||
casper.notebook_test(function () {
|
||||
"use strict";
|
||||
|
||||
var text = 'multi\nline';
|
||||
this.evaluate(function (text) {
|
||||
var cell = IPython.notebook.insert_cell_at_index('markdown', 0);
|
||||
cell.set_text(text);
|
||||
}, {text: text});
|
||||
|
||||
// Test markdown code blocks
|
||||
function mathjax_render_test(input_string, result, message){
|
||||
casper.thenEvaluate(function (text){
|
||||
window._test_result = null;
|
||||
require(['notebook/js/mathjaxutils'],function(mathjaxutils){
|
||||
window._test_result = mathjaxutils.remove_math(text);
|
||||
});
|
||||
}, {text: input_string});
|
||||
casper.waitFor(function() {
|
||||
return casper.evaluate(function(){
|
||||
return window._test_result!==null;
|
||||
});
|
||||
});
|
||||
casper.then(function(){
|
||||
var return_val = casper.evaluate(function(){
|
||||
var blah = window._test_result;
|
||||
delete window._test_result;
|
||||
return blah;
|
||||
});
|
||||
this.test.assertEquals(return_val[0], result[0], message+" markdown");
|
||||
this.test.assertEquals(return_val[1].length, result[1].length, message+" math instance count");
|
||||
for(var i=0; i<return_val[1].length; i++){
|
||||
this.test.assertEquals(return_val[1][i], result[1][i], message+" math instance "+i);
|
||||
};
|
||||
});
|
||||
};
|
||||
var input_string_1 = 'x \\\\(a_{0}+ b_{T}\\\\) y \\\\(a_{0}+ b_{T}\\\\) z';
|
||||
var expected_result_1 = ['x @@0@@ y @@1@@ z', ['\\\\(a_{0}+ b_{T}\\\\)','\\\\(a_{0}+ b_{T}\\\\)']];
|
||||
var message_1 = "multiple inline(LaTeX style) with underscores";
|
||||
|
||||
var input_string_2 = 'x \\\\[a_{0}+ b_{T}\\\\] y \\\\[a_{0}+ b_{T}\\\\] z';
|
||||
var expected_result_2 = ['x @@0@@ y @@1@@ z', ['\\\\[a_{0}+ b_{T}\\\\]','\\\\[a_{0}+ b_{T}\\\\]']];
|
||||
var message_2 = "multiple equation (LaTeX style) with underscores";
|
||||
|
||||
var input_string_3 = 'x $a_{0}+ b_{T}$ y $a_{0}+ b_{T}$ z';
|
||||
var expected_result_3 = ['x @@0@@ y @@1@@ z',['$a_{0}+ b_{T}$','$a_{0}+ b_{T}$']];
|
||||
var message_3 = "multiple inline(TeX style) with underscores";
|
||||
|
||||
var input_string_4 = 'x $$a_{0}+ b_{T}$$ y $$a_{0}+ b_{T}$$ z';
|
||||
var expected_result_4 = ['x @@0@@ y @@1@@ z', ['$$a_{0}+ b_{T}$$','$$a_{0}+ b_{T}$$']];
|
||||
var message_4 = "multiple equation(TeX style) with underscores";
|
||||
|
||||
var input_string_5 = 'x \\begin{equation}a_{0}+ b_{T}\\end{equation} y \\begin{equation}a_{0}+ b_{T}\\end{equation} z';
|
||||
var expected_result_5 = ['x @@0@@ y @@1@@ z',['\\begin{equation}a_{0}+ b_{T}\\end{equation}','\\begin{equation}a_{0}+ b_{T}\\end{equation}']];
|
||||
var message_5 = "multiple equations with underscores";
|
||||
|
||||
mathjax_render_test(input_string_1, expected_result_1, message_1);
|
||||
mathjax_render_test(input_string_2, expected_result_2, message_2);
|
||||
mathjax_render_test(input_string_3, expected_result_3, message_3);
|
||||
mathjax_render_test(input_string_4, expected_result_4, message_4);
|
||||
mathjax_render_test(input_string_5, expected_result_5, message_5);
|
||||
});
|
259
venv/Lib/site-packages/notebook/tests/notebook/output.js
Normal file
259
venv/Lib/site-packages/notebook/tests/notebook/output.js
Normal file
|
@ -0,0 +1,259 @@
|
|||
//
|
||||
// Various output tests
|
||||
//
|
||||
|
||||
casper.notebook_test(function () {
|
||||
|
||||
this.compare_outputs = function(results, expected) {
|
||||
for (var i = 0; i < results.length; i++) {
|
||||
var r = results[i];
|
||||
var ex = expected[i];
|
||||
this.test.assertEquals(r.output_type, ex.output_type, "output " + i + " = " + r.output_type);
|
||||
if (r.output_type === 'stream') {
|
||||
this.test.assertEquals(r.name, ex.name, "stream " + i + " = " + r.name);
|
||||
this.test.assertEquals(r.text, ex.text, "content " + i);
|
||||
}
|
||||
}
|
||||
}
|
||||
this.test_coalesced_output = function (msg, code, expected) {
|
||||
this.then(function () {
|
||||
this.echo("Test coalesced output: " + msg);
|
||||
});
|
||||
|
||||
this.thenEvaluate(function (code) {
|
||||
IPython.notebook.insert_cell_at_index("code", 0);
|
||||
var cell = IPython.notebook.get_cell(0);
|
||||
cell.set_text(code);
|
||||
cell.execute();
|
||||
}, {code: code});
|
||||
|
||||
this.wait_for_output(0);
|
||||
|
||||
this.then(function () {
|
||||
var results = this.evaluate(function () {
|
||||
var cell = IPython.notebook.get_cell(0);
|
||||
return cell.output_area.outputs;
|
||||
});
|
||||
this.test.assertEquals(results.length, expected.length, "correct number of outputs");
|
||||
this.compare_outputs(results, expected);
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
this.thenEvaluate(function () {
|
||||
IPython.notebook.insert_cell_at_index("code", 0);
|
||||
var cell = IPython.notebook.get_cell(0);
|
||||
cell.set_text([
|
||||
"from __future__ import print_function",
|
||||
"import sys",
|
||||
"from IPython.display import display, clear_output"
|
||||
].join("\n")
|
||||
);
|
||||
cell.execute();
|
||||
});
|
||||
|
||||
this.test_coalesced_output("stdout", [
|
||||
"print(1)",
|
||||
"sys.stdout.flush()",
|
||||
"print(2)",
|
||||
"sys.stdout.flush()",
|
||||
"print(3)"
|
||||
].join("\n"), [{
|
||||
output_type: "stream",
|
||||
name: "stdout",
|
||||
text: "1\n2\n3\n"
|
||||
}]
|
||||
);
|
||||
|
||||
this.test_coalesced_output("stdout+sdterr", [
|
||||
"print(1)",
|
||||
"sys.stdout.flush()",
|
||||
"print(2)",
|
||||
"print(3, file=sys.stderr)"
|
||||
].join("\n"), [{
|
||||
output_type: "stream",
|
||||
name: "stdout",
|
||||
text: "1\n2\n"
|
||||
},{
|
||||
output_type: "stream",
|
||||
name: "stderr",
|
||||
text: "3\n"
|
||||
}]
|
||||
);
|
||||
|
||||
this.test_coalesced_output("display splits streams", [
|
||||
"print(1)",
|
||||
"sys.stdout.flush()",
|
||||
"display(2)",
|
||||
"print(3)"
|
||||
].join("\n"), [{
|
||||
output_type: "stream",
|
||||
name: "stdout",
|
||||
text: "1\n"
|
||||
},{
|
||||
output_type: "display_data",
|
||||
},{
|
||||
output_type: "stream",
|
||||
name: "stdout",
|
||||
text: "3\n"
|
||||
}]
|
||||
);
|
||||
this.test_coalesced_output("test nested svg", [
|
||||
'from IPython.display import SVG',
|
||||
'nested_svg="""',
|
||||
'<svg xmlns="http://www.w3.org/2000/svg" width="200" height="100" >',
|
||||
' <svg x="0">',
|
||||
' <rect x="10" y="10" height="80" width="80" style="fill: #0000ff"/>',
|
||||
' </svg>',
|
||||
' <svg x="100">',
|
||||
' <rect x="10" y="10" height="80" width="80" style="fill: #00cc00"/>',
|
||||
' </svg>',
|
||||
'</svg>"""',
|
||||
'SVG(nested_svg)'
|
||||
].join("\n"), [{
|
||||
output_type: "execute_result",
|
||||
data: {
|
||||
"text/plain" : "<IPython.core.display.SVG object>",
|
||||
"image/svg+xml": [
|
||||
'<svg height="200" width="100" xmlns="http://www.w3.org/2000/svg">',
|
||||
' <svg x="0">',
|
||||
' <rect height="80" style="fill: #0000ff" width="80" x="10" y="10"/>',
|
||||
' </svg>',
|
||||
' <svg x="100">',
|
||||
' <rect height="80" style="fill: #00cc00" width="80" x="10" y="10"/>',
|
||||
' </svg>',
|
||||
'</svg>'].join("\n")
|
||||
},
|
||||
}]
|
||||
);
|
||||
|
||||
this.then(function () {
|
||||
this.echo("Test output callback overrides");
|
||||
});
|
||||
|
||||
this.thenEvaluate(function () {
|
||||
IPython.notebook.insert_cell_at_index("code", 0);
|
||||
var cell = IPython.notebook.get_cell(0);
|
||||
cell.set_text(["print(1)",
|
||||
"sys.stdout.flush()",
|
||||
"print(2)",
|
||||
"sys.stdout.flush()",
|
||||
"print(3, file=sys.stderr)",
|
||||
"sys.stdout.flush()",
|
||||
"display(2)",
|
||||
"clear_output()",
|
||||
"sys.stdout.flush()",
|
||||
"print('remove handler')",
|
||||
"sys.stdout.flush()",
|
||||
"print('back to cell')",
|
||||
"sys.stdout.flush()",
|
||||
].join('\n'));
|
||||
cell.execute();
|
||||
var kernel = IPython.notebook.kernel;
|
||||
var msg_id = cell.last_msg_id;
|
||||
var callback_id = 'mycallbackid'
|
||||
cell.iopub_messages = [];
|
||||
var add_msg = function(msg) {
|
||||
if (msg.content.text==="remove handler\n") {
|
||||
kernel.output_callback_overrides_pop(msg_id);
|
||||
}
|
||||
msg.content.output_type = msg.msg_type;
|
||||
cell.iopub_messages.push(msg.content);
|
||||
};
|
||||
kernel.set_callbacks_for_msg(callback_id, {
|
||||
iopub: {
|
||||
output: add_msg,
|
||||
clear_output: add_msg,
|
||||
}
|
||||
}, false);
|
||||
kernel.output_callback_overrides_push(msg_id, callback_id);
|
||||
});
|
||||
|
||||
this.wait_for_idle();
|
||||
|
||||
this.then(function () {
|
||||
var expected_callback = [{
|
||||
output_type: "stream",
|
||||
name: "stdout",
|
||||
text: "1\n"
|
||||
}, {
|
||||
output_type: "stream",
|
||||
name: "stdout",
|
||||
text: "2\n"
|
||||
}, {
|
||||
output_type: "stream",
|
||||
name: "stderr",
|
||||
text: "3\n"
|
||||
},{
|
||||
output_type: "display_data",
|
||||
},{
|
||||
output_type: "clear_output",
|
||||
},{
|
||||
output_type: "stream",
|
||||
name: "stdout",
|
||||
text: "remove handler\n"
|
||||
},]
|
||||
var expected_cell = [{
|
||||
output_type: "stream",
|
||||
name: "stdout",
|
||||
text: "back to cell\n"
|
||||
}]
|
||||
var returned = this.evaluate(function () {
|
||||
var cell = IPython.notebook.get_cell(0);
|
||||
return [cell.output_area.outputs, cell.iopub_messages];
|
||||
});
|
||||
var cell_results = returned[0];
|
||||
var callback_results = returned[1];
|
||||
this.test.assertEquals(cell_results.length, expected_cell.length, "correct number of cell outputs");
|
||||
this.test.assertEquals(callback_results.length, expected_callback.length, "correct number of callback outputs");
|
||||
this.compare_outputs(cell_results, expected_cell);
|
||||
this.compare_outputs(callback_results, expected_callback);
|
||||
});
|
||||
|
||||
this.then(function () {
|
||||
this.echo("Test output callback overrides get execute_results messages too");
|
||||
});
|
||||
|
||||
this.thenEvaluate(function () {
|
||||
IPython.notebook.insert_cell_at_index("code", 0);
|
||||
var cell = IPython.notebook.get_cell(0);
|
||||
cell.set_text("'end'");
|
||||
cell.execute();
|
||||
var kernel = IPython.notebook.kernel;
|
||||
var msg_id = cell.last_msg_id;
|
||||
var callback_id = 'mycallbackid2'
|
||||
cell.iopub_messages = [];
|
||||
var add_msg = function(msg) {
|
||||
msg.content.output_type = msg.msg_type;
|
||||
cell.iopub_messages.push(msg.content);
|
||||
};
|
||||
kernel.set_callbacks_for_msg(callback_id, {
|
||||
iopub: {
|
||||
output: add_msg,
|
||||
clear_output: add_msg,
|
||||
}
|
||||
}, false);
|
||||
kernel.output_callback_overrides_push(msg_id, callback_id);
|
||||
});
|
||||
|
||||
this.wait_for_idle();
|
||||
|
||||
this.then(function () {
|
||||
var expected_callback = [{
|
||||
output_type: "execute_result",
|
||||
data: {
|
||||
"text/plain" : "'end'"
|
||||
}
|
||||
}];
|
||||
var expected_cell = [];
|
||||
var returned = this.evaluate(function () {
|
||||
var cell = IPython.notebook.get_cell(0);
|
||||
return [cell.output_area.outputs, cell.iopub_messages];
|
||||
});
|
||||
var cell_results = returned[0];
|
||||
var callback_results = returned[1];
|
||||
this.test.assertEquals(cell_results.length, expected_cell.length, "correct number of cell outputs");
|
||||
this.test.assertEquals(callback_results.length, expected_callback.length, "correct number of callback outputs");
|
||||
this.compare_outputs(callback_results, expected_callback);
|
||||
});
|
||||
});
|
254
venv/Lib/site-packages/notebook/tests/notebook/roundtrip.js
Normal file
254
venv/Lib/site-packages/notebook/tests/notebook/roundtrip.js
Normal file
|
@ -0,0 +1,254 @@
|
|||
// Test opening a rich notebook, saving it, and reopening it again.
|
||||
//
|
||||
//toJSON fromJSON toJSON and do a string comparison
|
||||
|
||||
|
||||
// this is just a copy of OutputArea.mime_mape_r in IPython/html/static/notebook/js/outputarea.js
|
||||
mime = {
|
||||
"text" : "text/plain",
|
||||
"html" : "text/html",
|
||||
"svg" : "image/svg+xml",
|
||||
"png" : "image/png",
|
||||
"jpeg" : "image/jpeg",
|
||||
"latex" : "text/latex",
|
||||
"json" : "application/json",
|
||||
"javascript" : "application/javascript",
|
||||
};
|
||||
|
||||
var black_dot_jpeg="u\"\"\"/9j/4AAQSkZJRgABAQEASABIAAD/2wBDACodICUgGiolIiUvLSoyP2lEPzo6P4FcYUxpmYagnpaG\nk5GovfLNqLPltZGT0v/V5fr/////o8v///////L/////2wBDAS0vLz83P3xERHz/rpOu////////\n////////////////////////////////////////////////////////////wgARCAABAAEDAREA\nAhEBAxEB/8QAFAABAAAAAAAAAAAAAAAAAAAABP/EABQBAQAAAAAAAAAAAAAAAAAAAAD/2gAMAwEA\nAhADEAAAARn/xAAUEAEAAAAAAAAAAAAAAAAAAAAA/9oACAEBAAEFAn//xAAUEQEAAAAAAAAAAAAA\nAAAAAAAA/9oACAEDAQE/AX//xAAUEQEAAAAAAAAAAAAAAAAAAAAA/9oACAECAQE/AX//xAAUEAEA\nAAAAAAAAAAAAAAAAAAAA/9oACAEBAAY/An//xAAUEAEAAAAAAAAAAAAAAAAAAAAA/9oACAEBAAE/\nIX//2gAMAwEAAgADAAAAEB//xAAUEQEAAAAAAAAAAAAAAAAAAAAA/9oACAEDAQE/EH//xAAUEQEA\nAAAAAAAAAAAAAAAAAAAA/9oACAECAQE/EH//xAAUEAEAAAAAAAAAAAAAAAAAAAAA/9oACAEBAAE/\nEH//2Q==\"\"\"";
|
||||
var black_dot_png = 'u\"iVBORw0KGgoAAAANSUhEUgAAAAEAAAABAQMAAAAl21bKAAAAA1BMVEUAAACnej3aAAAAAWJLR0QA\\niAUdSAAAAAlwSFlzAAALEwAACxMBAJqcGAAAAAd0SU1FB94BCRQnOqNu0b4AAAAKSURBVAjXY2AA\\nAAACAAHiIbwzAAAAAElFTkSuQmCC\"';
|
||||
var svg = "\"<svg width='1cm' height='1cm' viewBox='0 0 1000 500'><defs><style>rect {fill:red;}; </style></defs><rect id='r1' x='200' y='100' width='600' height='300' /></svg>\"";
|
||||
|
||||
// helper function to ensure that the short_name is found in the toJSON
|
||||
// representation, while the original in-memory cell retains its long mimetype
|
||||
// name, and that fromJSON also gets its long mimetype name
|
||||
function assert_has(short_name, json, result, result2) {
|
||||
var long_name = mime[short_name];
|
||||
this.test.assertFalse(json[0].data.hasOwnProperty(short_name),
|
||||
"toJSON() representation doesn't use " + short_name);
|
||||
this.test.assertTrue(json[0].data.hasOwnProperty(long_name),
|
||||
'toJSON() representation uses ' + long_name);
|
||||
this.test.assertTrue(result.data.hasOwnProperty(long_name),
|
||||
'toJSON() original embedded JSON keeps ' + long_name);
|
||||
this.test.assertTrue(result2.data.hasOwnProperty(long_name),
|
||||
'fromJSON() embedded ' + short_name + ' gets mime key ' + long_name);
|
||||
}
|
||||
|
||||
// helper function for checkout that the first two cells have a particular
|
||||
// output_type (either 'execute_result' or 'display_data'), and checks the to/fromJSON
|
||||
// for a set of mimetype keys, ensuring the old short names ('javascript', 'text',
|
||||
// 'png', etc) are not used.
|
||||
function check_output_area(output_type, keys) {
|
||||
this.wait_for_output(0);
|
||||
var json = this.evaluate(function() {
|
||||
var json = IPython.notebook.get_cell(0).output_area.toJSON();
|
||||
// appended cell will initially be empty, let's add some output
|
||||
IPython.notebook.get_cell(1).output_area.fromJSON(json);
|
||||
return json;
|
||||
});
|
||||
// The evaluate call above happens asynchronously: wait for cell[1] to have output
|
||||
this.wait_for_output(1);
|
||||
var result = this.get_output_cell(0);
|
||||
var result2 = this.get_output_cell(1);
|
||||
this.test.assertEquals(result.output_type, output_type,
|
||||
'testing ' + output_type + ' for ' + keys.join(' and '));
|
||||
|
||||
for (var idx in keys) {
|
||||
assert_has.apply(this, [keys[idx], json, result, result2]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// helper function to clear the first two cells, set the text of and execute
|
||||
// the first one
|
||||
function clear_and_execute(that, code) {
|
||||
that.evaluate(function() {
|
||||
IPython.notebook.get_cell(0).clear_output();
|
||||
IPython.notebook.get_cell(1).clear_output();
|
||||
});
|
||||
that.then(function () {
|
||||
that.set_cell_text(0, code);
|
||||
that.execute_cell(0);
|
||||
that.wait_for_idle();
|
||||
});
|
||||
}
|
||||
|
||||
casper.notebook_test(function () {
|
||||
this.evaluate(function () {
|
||||
var cell = IPython.notebook.get_cell(0);
|
||||
// "we have to make messes to find out who we are"
|
||||
cell.set_text([
|
||||
"%%javascript",
|
||||
"IPython.notebook.insert_cell_below('code')"
|
||||
].join('\n')
|
||||
);
|
||||
});
|
||||
|
||||
this.execute_cell_then(0, function () {
|
||||
var result = this.get_output_cell(0);
|
||||
var num_cells = this.get_cells_length();
|
||||
this.test.assertEquals(num_cells, 2, '%%javascript magic works');
|
||||
this.test.assertTrue(result.data.hasOwnProperty('application/javascript'),
|
||||
'testing JS embedded with mime key');
|
||||
});
|
||||
|
||||
//this.thenEvaluate(function() { IPython.notebook.save_notebook(); });
|
||||
this.then(function () {
|
||||
clear_and_execute(this, [
|
||||
"%%javascript",
|
||||
"var a=5;"
|
||||
].join('\n'));
|
||||
});
|
||||
|
||||
|
||||
this.then(function () {
|
||||
check_output_area.apply(this, ['display_data', ['javascript']]);
|
||||
|
||||
});
|
||||
|
||||
this.then(function() {
|
||||
clear_and_execute(this, '%lsmagic');
|
||||
});
|
||||
|
||||
this.then(function () {
|
||||
check_output_area.apply(this, ['execute_result', ['text', 'json']]);
|
||||
});
|
||||
|
||||
this.then(function() {
|
||||
clear_and_execute(this,
|
||||
"x = %lsmagic\nfrom IPython.display import display; display(x)");
|
||||
});
|
||||
|
||||
this.then(function ( ) {
|
||||
check_output_area.apply(this, ['display_data', ['text', 'json']]);
|
||||
});
|
||||
|
||||
this.then(function() {
|
||||
clear_and_execute(this,
|
||||
"from IPython.display import Latex; Latex('$X^2$')");
|
||||
});
|
||||
|
||||
this.then(function ( ) {
|
||||
check_output_area.apply(this, ['execute_result', ['text', 'latex']]);
|
||||
});
|
||||
|
||||
this.then(function() {
|
||||
clear_and_execute(this,
|
||||
"from IPython.display import Latex, display; display(Latex('$X^2$'))");
|
||||
});
|
||||
|
||||
this.then(function ( ) {
|
||||
check_output_area.apply(this, ['display_data', ['text', 'latex']]);
|
||||
});
|
||||
|
||||
this.then(function() {
|
||||
clear_and_execute(this,
|
||||
"from IPython.display import HTML; HTML('<b>it works!</b>')");
|
||||
});
|
||||
|
||||
this.then(function ( ) {
|
||||
check_output_area.apply(this, ['execute_result', ['text', 'html']]);
|
||||
});
|
||||
|
||||
this.then(function() {
|
||||
clear_and_execute(this,
|
||||
"from base64 import b64decode;" +
|
||||
"black_dot_png = b64decode(" + black_dot_png + ");" +
|
||||
"black_dot_jpeg = b64decode(" + black_dot_jpeg + ")"
|
||||
);
|
||||
});
|
||||
this.then(function() {
|
||||
clear_and_execute(this,
|
||||
"from IPython.display import HTML, display; display(HTML('<b>it works!</b>'))");
|
||||
});
|
||||
|
||||
this.then(function ( ) {
|
||||
check_output_area.apply(this, ['display_data', ['text', 'html']]);
|
||||
});
|
||||
|
||||
|
||||
this.then(function() {
|
||||
clear_and_execute(this,
|
||||
"from IPython.display import Image; Image(black_dot_png)");
|
||||
});
|
||||
this.thenEvaluate(function() { IPython.notebook.save_notebook(); });
|
||||
|
||||
this.then(function ( ) {
|
||||
check_output_area.apply(this, ['execute_result', ['text', 'png']]);
|
||||
});
|
||||
|
||||
this.then(function() {
|
||||
clear_and_execute(this,
|
||||
"from IPython.display import Image, display; display(Image(black_dot_png))");
|
||||
});
|
||||
|
||||
this.then(function ( ) {
|
||||
check_output_area.apply(this, ['display_data', ['text', 'png']]);
|
||||
});
|
||||
|
||||
|
||||
this.then(function() {
|
||||
clear_and_execute(this,
|
||||
"from IPython.display import Image; Image(black_dot_jpeg, format='jpeg')");
|
||||
});
|
||||
|
||||
this.then(function ( ) {
|
||||
check_output_area.apply(this, ['execute_result', ['text', 'jpeg']]);
|
||||
});
|
||||
|
||||
this.then(function() {
|
||||
clear_and_execute(this,
|
||||
"from IPython.display import Image, display; display(Image(black_dot_jpeg, format='jpeg'))");
|
||||
});
|
||||
|
||||
this.then(function ( ) {
|
||||
check_output_area.apply(this, ['display_data', ['text', 'jpeg']]);
|
||||
});
|
||||
|
||||
this.then(function() {
|
||||
clear_and_execute(this,
|
||||
"from IPython.core.display import SVG; SVG(" + svg + ")");
|
||||
});
|
||||
|
||||
this.then(function ( ) {
|
||||
check_output_area.apply(this, ['execute_result', ['text', 'svg']]);
|
||||
});
|
||||
|
||||
this.then(function() {
|
||||
clear_and_execute(this,
|
||||
"from IPython.core.display import SVG, display; display(SVG(" + svg + "))");
|
||||
});
|
||||
|
||||
this.then(function ( ) {
|
||||
check_output_area.apply(this, ['display_data', ['text', 'svg']]);
|
||||
});
|
||||
|
||||
this.thenEvaluate(function() { IPython.notebook.save_notebook(); });
|
||||
|
||||
this.then(function() {
|
||||
clear_and_execute(this, [
|
||||
"from IPython.core.formatters import HTMLFormatter",
|
||||
"x = HTMLFormatter()",
|
||||
"x.format_type = 'text/superfancymimetype'",
|
||||
"get_ipython().display_formatter.formatters['text/superfancymimetype'] = x",
|
||||
"from IPython.display import HTML, display",
|
||||
'display(HTML("yo"))',
|
||||
"HTML('hello')"].join('\n')
|
||||
);
|
||||
|
||||
});
|
||||
|
||||
this.wait_for_output(0, 1);
|
||||
|
||||
this.then(function () {
|
||||
var long_name = 'text/superfancymimetype';
|
||||
var result = this.get_output_cell(0);
|
||||
this.test.assertTrue(result.data.hasOwnProperty(long_name),
|
||||
'display_data custom mimetype ' + long_name);
|
||||
result = this.get_output_cell(0, 1);
|
||||
this.test.assertTrue(result.data.hasOwnProperty(long_name),
|
||||
'execute_result custom mimetype ' + long_name);
|
||||
|
||||
});
|
||||
|
||||
});
|
|
@ -0,0 +1,32 @@
|
|||
//
|
||||
// Test validation in append_output
|
||||
//
|
||||
// Invalid output data is stripped and logged.
|
||||
//
|
||||
|
||||
casper.notebook_test(function () {
|
||||
// this.printLog();
|
||||
var messages = [];
|
||||
this.on('remote.message', function (msg) {
|
||||
messages.push(msg);
|
||||
});
|
||||
|
||||
this.evaluate(function () {
|
||||
var cell = IPython.notebook.get_cell(0);
|
||||
cell.set_text( "dp = get_ipython().display_pub\n" +
|
||||
"dp.publish({'text/plain' : '5', 'image/png' : 5})"
|
||||
);
|
||||
cell.execute();
|
||||
});
|
||||
|
||||
this.wait_for_output(0);
|
||||
this.on('remote.message', function () {});
|
||||
|
||||
this.then(function () {
|
||||
var output = this.get_output_cell(0);
|
||||
this.test.assert(messages.length > 0, "Captured log message");
|
||||
this.test.assertEquals(messages[messages.length-1].substr(0,26), "Invalid type for image/png", "Logged Invalid type message");
|
||||
this.test.assertEquals(output.data['image/png'], undefined, "Non-string png data was stripped");
|
||||
this.test.assertEquals(output.data['text/plain'], '5', "text data is fine");
|
||||
});
|
||||
});
|
123
venv/Lib/site-packages/notebook/tests/notebook/tags.js
Normal file
123
venv/Lib/site-packages/notebook/tests/notebook/tags.js
Normal file
|
@ -0,0 +1,123 @@
|
|||
//
|
||||
// Various tagging
|
||||
//
|
||||
|
||||
casper.notebook_test(function () {
|
||||
|
||||
function get_tag_metadata () {
|
||||
return casper.evaluate(function () {
|
||||
return Jupyter.notebook.get_cell(0).metadata.tags;
|
||||
});
|
||||
}
|
||||
|
||||
function get_tag_elements () {
|
||||
return casper.evaluate(function () {
|
||||
var cell = Jupyter.notebook.get_cell(0);
|
||||
return $.map(
|
||||
cell.element.find('.cell-tag'),
|
||||
function (el) {
|
||||
return $(el.childNodes[0]).text();
|
||||
}
|
||||
);
|
||||
})
|
||||
}
|
||||
// wait for cell toolbar item to be present (necessary?)
|
||||
this.waitFor(function () {
|
||||
return this.evaluate(function() {
|
||||
return $('#menu-cell-toolbar-submenu')
|
||||
.find('[data-name=Tags]')
|
||||
.length;
|
||||
});
|
||||
});
|
||||
this.then(function () {
|
||||
var tag_items = this.evaluate(function() {
|
||||
return $('#menu-cell-toolbar-submenu')
|
||||
.find('[data-name=Tags]')
|
||||
.length;
|
||||
});
|
||||
this.test.assertEquals(
|
||||
tag_items,
|
||||
1,
|
||||
"Tag cell toolbar item is present");
|
||||
})
|
||||
|
||||
// activate tags toolbar via menubar
|
||||
this.thenEvaluate(function () {
|
||||
$('#menu-cell-toolbar-submenu')
|
||||
.find('[data-name=Tags]')
|
||||
.find('a')
|
||||
.click();
|
||||
});
|
||||
|
||||
// wait for one tag container
|
||||
this.waitForSelector('.tags_button_container');
|
||||
this.then(function () {
|
||||
var elements = this.evaluate(function () {
|
||||
var cell = Jupyter.notebook.get_cell(0);
|
||||
var tag_input = cell.element
|
||||
.find('.tags-input input');
|
||||
return tag_input.length;
|
||||
})
|
||||
this.test.assertEquals(
|
||||
elements,
|
||||
1,
|
||||
"tags-input element exists");
|
||||
})
|
||||
|
||||
// apply some tags
|
||||
this.thenEvaluate(function () {
|
||||
var cell = Jupyter.notebook.get_cell(0);
|
||||
var tag_input = cell.element
|
||||
.find('.tags-input input');
|
||||
// add some tags separated by commas and spaces,
|
||||
// including duplicates
|
||||
tag_input.val('tag1, tüg2 tåg3,tag4,,,tag5 tag1');
|
||||
cell.element
|
||||
.find('.tags-input button')
|
||||
.click();
|
||||
});
|
||||
|
||||
var all_tags = ['tag1', 'tüg2', 'tåg3', 'tag4', 'tag5'];
|
||||
// verify that tags are applied
|
||||
this.then(function () {
|
||||
var tags = get_tag_metadata();
|
||||
this.test.assertEquals(
|
||||
tags,
|
||||
all_tags,
|
||||
"tags have been applied to metadata"
|
||||
);
|
||||
|
||||
var tag_elements = get_tag_elements();
|
||||
this.test.assertEquals(
|
||||
tag_elements,
|
||||
all_tags,
|
||||
"tags elements have been added"
|
||||
);
|
||||
});
|
||||
|
||||
// remove first tag by clicking 'X'
|
||||
this.thenEvaluate(function () {
|
||||
var cell = Jupyter.notebook.get_cell(0);
|
||||
var X = cell.element
|
||||
.find('.tag-container .remove-tag-btn')
|
||||
.first();
|
||||
X.click();
|
||||
});
|
||||
|
||||
this.then(function () {
|
||||
var expected_tags = all_tags.slice(1);
|
||||
var tags = get_tag_metadata();
|
||||
this.test.assertEquals(
|
||||
tags,
|
||||
expected_tags,
|
||||
"clicking X removes tags from metadata"
|
||||
);
|
||||
|
||||
var tag_elements = get_tag_elements();
|
||||
this.test.assertEquals(
|
||||
tag_elements,
|
||||
expected_tags,
|
||||
"clicking X removes tags from UI"
|
||||
);
|
||||
})
|
||||
});
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
143
venv/Lib/site-packages/notebook/tests/selenium/conftest.py
Normal file
143
venv/Lib/site-packages/notebook/tests/selenium/conftest.py
Normal file
|
@ -0,0 +1,143 @@
|
|||
import json
|
||||
import nbformat
|
||||
from nbformat.v4 import new_notebook, new_code_cell
|
||||
import os
|
||||
import pytest
|
||||
import requests
|
||||
from subprocess import Popen
|
||||
import sys
|
||||
from tempfile import mkstemp
|
||||
from testpath.tempdir import TemporaryDirectory
|
||||
import time
|
||||
from urllib.parse import urljoin
|
||||
|
||||
from selenium.webdriver import Firefox, Remote, Chrome
|
||||
from .utils import Notebook
|
||||
|
||||
pjoin = os.path.join
|
||||
|
||||
|
||||
def _wait_for_server(proc, info_file_path):
|
||||
"""Wait 30 seconds for the notebook server to start"""
|
||||
for i in range(300):
|
||||
if proc.poll() is not None:
|
||||
raise RuntimeError("Notebook server failed to start")
|
||||
if os.path.exists(info_file_path):
|
||||
try:
|
||||
with open(info_file_path) as f:
|
||||
return json.load(f)
|
||||
except ValueError:
|
||||
# If the server is halfway through writing the file, we may
|
||||
# get invalid JSON; it should be ready next iteration.
|
||||
pass
|
||||
time.sleep(0.1)
|
||||
raise RuntimeError("Didn't find %s in 30 seconds", info_file_path)
|
||||
|
||||
|
||||
@pytest.fixture(scope='session')
|
||||
def notebook_server():
|
||||
info = {}
|
||||
with TemporaryDirectory() as td:
|
||||
nbdir = info['nbdir'] = pjoin(td, 'notebooks')
|
||||
os.makedirs(pjoin(nbdir, u'sub ∂ir1', u'sub ∂ir 1a'))
|
||||
os.makedirs(pjoin(nbdir, u'sub ∂ir2', u'sub ∂ir 1b'))
|
||||
|
||||
info['extra_env'] = {
|
||||
'JUPYTER_CONFIG_DIR': pjoin(td, 'jupyter_config'),
|
||||
'JUPYTER_RUNTIME_DIR': pjoin(td, 'jupyter_runtime'),
|
||||
'IPYTHONDIR': pjoin(td, 'ipython'),
|
||||
}
|
||||
env = os.environ.copy()
|
||||
env.update(info['extra_env'])
|
||||
|
||||
command = [sys.executable, '-m', 'notebook',
|
||||
'--no-browser',
|
||||
'--notebook-dir', nbdir,
|
||||
# run with a base URL that would be escaped,
|
||||
# to test that we don't double-escape URLs
|
||||
'--NotebookApp.base_url=/a@b/',
|
||||
]
|
||||
print("command=", command)
|
||||
proc = info['popen'] = Popen(command, cwd=nbdir, env=env)
|
||||
info_file_path = pjoin(td, 'jupyter_runtime',
|
||||
'nbserver-%i.json' % proc.pid)
|
||||
info.update(_wait_for_server(proc, info_file_path))
|
||||
|
||||
print("Notebook server info:", info)
|
||||
yield info
|
||||
|
||||
# Shut the server down
|
||||
requests.post(urljoin(info['url'], 'api/shutdown'),
|
||||
headers={'Authorization': 'token '+info['token']})
|
||||
|
||||
|
||||
def make_sauce_driver():
|
||||
"""This function helps travis create a driver on Sauce Labs.
|
||||
|
||||
This function will err if used without specifying the variables expected
|
||||
in that context.
|
||||
"""
|
||||
|
||||
username = os.environ["SAUCE_USERNAME"]
|
||||
access_key = os.environ["SAUCE_ACCESS_KEY"]
|
||||
capabilities = {
|
||||
"tunnel-identifier": os.environ["TRAVIS_JOB_NUMBER"],
|
||||
"build": os.environ["TRAVIS_BUILD_NUMBER"],
|
||||
"tags": [os.environ['TRAVIS_PYTHON_VERSION'], 'CI'],
|
||||
"platform": "Windows 10",
|
||||
"browserName": os.environ['JUPYTER_TEST_BROWSER'],
|
||||
"version": "latest",
|
||||
}
|
||||
if capabilities['browserName'] == 'firefox':
|
||||
# Attempt to work around issue where browser loses authentication
|
||||
capabilities['version'] = '57.0'
|
||||
hub_url = "%s:%s@localhost:4445" % (username, access_key)
|
||||
print("Connecting remote driver on Sauce Labs")
|
||||
driver = Remote(desired_capabilities=capabilities,
|
||||
command_executor="http://%s/wd/hub" % hub_url)
|
||||
return driver
|
||||
|
||||
|
||||
@pytest.fixture(scope='session')
|
||||
def selenium_driver():
|
||||
if os.environ.get('SAUCE_USERNAME'):
|
||||
driver = make_sauce_driver()
|
||||
elif os.environ.get('JUPYTER_TEST_BROWSER') == 'chrome':
|
||||
driver = Chrome()
|
||||
else:
|
||||
driver = Firefox()
|
||||
|
||||
yield driver
|
||||
|
||||
# Teardown
|
||||
driver.quit()
|
||||
|
||||
|
||||
@pytest.fixture(scope='module')
|
||||
def authenticated_browser(selenium_driver, notebook_server):
|
||||
selenium_driver.jupyter_server_info = notebook_server
|
||||
selenium_driver.get("{url}?token={token}".format(**notebook_server))
|
||||
return selenium_driver
|
||||
|
||||
@pytest.fixture
|
||||
def notebook(authenticated_browser):
|
||||
tree_wh = authenticated_browser.current_window_handle
|
||||
yield Notebook.new_notebook(authenticated_browser)
|
||||
authenticated_browser.switch_to.window(tree_wh)
|
||||
|
||||
@pytest.fixture
|
||||
def prefill_notebook(selenium_driver, notebook_server):
|
||||
def inner(cells):
|
||||
cells = [new_code_cell(c) if isinstance(c, str) else c
|
||||
for c in cells]
|
||||
nb = new_notebook(cells=cells)
|
||||
fd, path = mkstemp(dir=notebook_server['nbdir'], suffix='.ipynb')
|
||||
with open(fd, 'w', encoding='utf-8') as f:
|
||||
nbformat.write(nb, f)
|
||||
fname = os.path.basename(path)
|
||||
selenium_driver.get(
|
||||
"{url}notebooks/{}?token={token}".format(fname, **notebook_server)
|
||||
)
|
||||
return Notebook(selenium_driver)
|
||||
|
||||
return inner
|
|
@ -0,0 +1,53 @@
|
|||
"""Utilities for driving Selenium interactively to develop tests.
|
||||
|
||||
These are not used in the tests themselves - rather, the developer writing tests
|
||||
can use them to experiment with Selenium.
|
||||
"""
|
||||
from selenium.webdriver import Firefox
|
||||
|
||||
from notebook.tests.selenium.utils import Notebook
|
||||
from notebook.notebookapp import list_running_servers
|
||||
|
||||
class NoServerError(Exception):
|
||||
|
||||
def __init__(self, message):
|
||||
self.message = message
|
||||
|
||||
def quick_driver(lab=False):
|
||||
"""Quickly create a selenium driver pointing at an active noteboook server.
|
||||
|
||||
Usage example:
|
||||
|
||||
from notebook.tests.selenium.quick_selenium import quick_driver
|
||||
driver = quick_driver
|
||||
|
||||
Note: you need to manually close the driver that opens with driver.quit()
|
||||
"""
|
||||
try:
|
||||
server = list(list_running_servers())[0]
|
||||
except IndexError as e:
|
||||
raise NoServerError('You need a server running before you can run '
|
||||
'this command') from e
|
||||
driver = Firefox()
|
||||
auth_url = '{url}?token={token}'.format(**server)
|
||||
driver.get(auth_url)
|
||||
|
||||
# If this redirects us to a lab page and we don't want that;
|
||||
# then we need to redirect ourselves to the classic notebook view
|
||||
if driver.current_url.endswith('/lab') and not lab:
|
||||
driver.get(driver.current_url.rstrip('lab')+'tree')
|
||||
return driver
|
||||
|
||||
|
||||
def quick_notebook():
|
||||
"""Quickly create a new classic notebook in a selenium driver
|
||||
|
||||
|
||||
Usage example:
|
||||
|
||||
from notebook.tests.selenium.quick_selenium import quick_notebook
|
||||
nb = quick_notebook()
|
||||
|
||||
Note: you need to manually close the driver that opens with nb.browser.quit()
|
||||
"""
|
||||
return Notebook.new_notebook(quick_driver())
|
|
@ -0,0 +1,50 @@
|
|||
"""Tests buffering of execution requests."""
|
||||
|
||||
from .utils import wait_for_selector
|
||||
|
||||
|
||||
def wait_for_cell_text_output(notebook, index):
|
||||
cell = notebook.cells[index]
|
||||
output = wait_for_selector(cell, ".output_text", single=True)
|
||||
return output.text
|
||||
|
||||
|
||||
def wait_for_kernel_ready(notebook):
|
||||
wait_for_selector(notebook.browser, ".kernel_idle_icon")
|
||||
|
||||
|
||||
def test_kernels_buffer_without_conn(prefill_notebook):
|
||||
"""Test that execution request made while disconnected is buffered."""
|
||||
notebook = prefill_notebook(["print(1 + 2)"])
|
||||
|
||||
wait_for_kernel_ready(notebook)
|
||||
notebook.browser.execute_script("IPython.notebook.kernel.stop_channels();")
|
||||
notebook.execute_cell(0)
|
||||
notebook.browser.execute_script("IPython.notebook.kernel.reconnect();")
|
||||
wait_for_kernel_ready(notebook)
|
||||
|
||||
assert wait_for_cell_text_output(notebook, 0) == "3"
|
||||
|
||||
|
||||
def test_buffered_cells_execute_in_order(prefill_notebook):
|
||||
"""Test that buffered requests execute in order."""
|
||||
notebook = prefill_notebook(['', 'k=1', 'k+=1', 'k*=3', 'print(k)'])
|
||||
|
||||
# Repeated execution of cell queued up in the kernel executes
|
||||
# each execution request in order.
|
||||
wait_for_kernel_ready(notebook)
|
||||
notebook.browser.execute_script("IPython.notebook.kernel.stop_channels();")
|
||||
# k == 1
|
||||
notebook.execute_cell(1)
|
||||
# k == 2
|
||||
notebook.execute_cell(2)
|
||||
# k == 6
|
||||
notebook.execute_cell(3)
|
||||
# k == 7
|
||||
notebook.execute_cell(2)
|
||||
notebook.execute_cell(4)
|
||||
notebook.browser.execute_script("IPython.notebook.kernel.reconnect();")
|
||||
wait_for_kernel_ready(notebook)
|
||||
|
||||
# Check that current value of k is 7
|
||||
assert wait_for_cell_text_output(notebook, 4) == "7"
|
|
@ -0,0 +1,27 @@
|
|||
"""Tests clipboard by copying, cutting and pasting multiple cells"""
|
||||
from selenium.webdriver.common.keys import Keys
|
||||
from .utils import wait_for_selector, wait_for_xpath
|
||||
|
||||
def test_clipboard_multiselect(prefill_notebook):
|
||||
notebook = prefill_notebook(['', '1', '2', '3', '4', '5a', '6b', '7c', '8d'])
|
||||
|
||||
assert notebook.get_cells_contents() == ['', '1', '2', '3', '4', '5a', '6b', '7c', '8d']
|
||||
|
||||
# Select the first 3 cells with value and replace the last 3
|
||||
[notebook.body.send_keys(Keys.UP) for i in range(8)]
|
||||
notebook.select_cell_range(1, 3)
|
||||
notebook.body.send_keys("c")
|
||||
notebook.select_cell_range(6, 8)
|
||||
wait_for_xpath(notebook.browser, '//a[text()="Edit"]', single=True).click()
|
||||
wait_for_selector(notebook.browser, '#paste_cell_replace', single=True).click()
|
||||
|
||||
assert notebook.get_cells_contents() == ['', '1', '2', '3', '4', '5a', '1', '2', '3']
|
||||
|
||||
# Select the last four cells, cut them and paste them below the first cell
|
||||
notebook.select_cell_range(5, 8)
|
||||
wait_for_selector(notebook.browser, '.fa-cut.fa', single=True).click()
|
||||
for i in range(8):
|
||||
notebook.body.send_keys(Keys.UP)
|
||||
notebook.body.send_keys("v")
|
||||
|
||||
assert notebook.get_cells_contents() == ['', '5a', '1', '2', '3', '1', '2', '3', '4']
|
|
@ -0,0 +1,73 @@
|
|||
import os
|
||||
|
||||
from selenium.webdriver.common.by import By
|
||||
from selenium.webdriver.support.ui import WebDriverWait
|
||||
from selenium.webdriver.support import expected_conditions as EC
|
||||
|
||||
from notebook.utils import url_path_join
|
||||
from notebook.tests.selenium.utils import wait_for_selector
|
||||
pjoin = os.path.join
|
||||
|
||||
|
||||
class PageError(Exception):
|
||||
"""Error for an action being incompatible with the current jupyter web page.
|
||||
|
||||
"""
|
||||
def __init__(self, message):
|
||||
self.message = message
|
||||
|
||||
|
||||
def url_in_tree(browser, url=None):
|
||||
if url is None:
|
||||
url = browser.current_url
|
||||
tree_url = url_path_join(browser.jupyter_server_info['url'], 'tree')
|
||||
return url.startswith(tree_url)
|
||||
|
||||
|
||||
def get_list_items(browser):
|
||||
"""Gets list items from a directory listing page
|
||||
|
||||
Raises PageError if not in directory listing page (url has tree in it)
|
||||
"""
|
||||
if not url_in_tree(browser):
|
||||
raise PageError("You are not in the notebook's file tree view."
|
||||
"This function can only be used the file tree context.")
|
||||
# we need to make sure that at least one item link loads
|
||||
wait_for_selector(browser, '.item_link')
|
||||
|
||||
return [{
|
||||
'link': a.get_attribute('href'),
|
||||
'label': a.find_element_by_class_name('item_name').text,
|
||||
'element': a,
|
||||
} for a in browser.find_elements_by_class_name('item_link')]
|
||||
|
||||
def only_dir_links(browser):
|
||||
"""Return only links that point at other directories in the tree
|
||||
|
||||
"""
|
||||
items = get_list_items(browser)
|
||||
return [i for i in items
|
||||
if url_in_tree(browser, i['link']) and i['label'] != '..']
|
||||
|
||||
def test_items(authenticated_browser):
|
||||
visited_dict = {}
|
||||
# Going down the tree to collect links
|
||||
while True:
|
||||
wait_for_selector(authenticated_browser, '.item_link')
|
||||
current_url = authenticated_browser.current_url
|
||||
items = visited_dict[current_url] = only_dir_links(authenticated_browser)
|
||||
try:
|
||||
item = items[0]
|
||||
item["element"].click()
|
||||
assert authenticated_browser.current_url == item['link']
|
||||
except IndexError:
|
||||
break
|
||||
# Going back up the tree while we still have unvisited links
|
||||
while visited_dict:
|
||||
current_items = only_dir_links(authenticated_browser)
|
||||
current_items_links = [item["link"] for item in current_items]
|
||||
stored_items = visited_dict.pop(authenticated_browser.current_url)
|
||||
stored_items_links = [item["link"] for item in stored_items]
|
||||
assert stored_items_links == current_items_links
|
||||
authenticated_browser.back()
|
||||
|
|
@ -0,0 +1,58 @@
|
|||
|
||||
def cell_is_deletable(nb, index):
|
||||
JS = 'return Jupyter.notebook.get_cell({}).is_deletable();'.format(index)
|
||||
return nb.browser.execute_script(JS)
|
||||
|
||||
def remove_all_cells(notebook):
|
||||
for i in range(len(notebook.cells)):
|
||||
notebook.delete_cell(0)
|
||||
|
||||
INITIAL_CELLS = ['print("a")', 'print("b")', 'print("c")']
|
||||
|
||||
def test_delete_cells(prefill_notebook):
|
||||
a, b, c = INITIAL_CELLS
|
||||
notebook = prefill_notebook(INITIAL_CELLS)
|
||||
|
||||
# Validate initial state
|
||||
assert notebook.get_cells_contents() == [a, b, c]
|
||||
for cell in range(0, 3):
|
||||
assert cell_is_deletable(notebook, cell)
|
||||
|
||||
notebook.set_cell_metadata(0, 'deletable', 'false')
|
||||
notebook.set_cell_metadata(1, 'deletable', 0
|
||||
)
|
||||
assert not cell_is_deletable(notebook, 0)
|
||||
assert cell_is_deletable(notebook, 1)
|
||||
assert cell_is_deletable(notebook, 2)
|
||||
|
||||
# Try to delete cell a (should not be deleted)
|
||||
notebook.delete_cell(0)
|
||||
assert notebook.get_cells_contents() == [a, b, c]
|
||||
|
||||
# Try to delete cell b (should succeed)
|
||||
notebook.delete_cell(1)
|
||||
assert notebook.get_cells_contents() == [a, c]
|
||||
|
||||
# Try to delete cell c (should succeed)
|
||||
notebook.delete_cell(1)
|
||||
assert notebook.get_cells_contents() == [a]
|
||||
|
||||
# Change the deletable state of cell a
|
||||
notebook.set_cell_metadata(0, 'deletable', 'true')
|
||||
|
||||
# Try to delete cell a (should succeed)
|
||||
notebook.delete_cell(0)
|
||||
assert len(notebook.cells) == 1 # it contains an empty cell
|
||||
|
||||
# Make sure copied cells are deletable
|
||||
notebook.edit_cell(index=0, content=a)
|
||||
notebook.set_cell_metadata(0, 'deletable', 'false')
|
||||
assert not cell_is_deletable(notebook, 0)
|
||||
notebook.to_command_mode()
|
||||
notebook.current_cell.send_keys('cv')
|
||||
assert len(notebook.cells) == 2
|
||||
assert cell_is_deletable(notebook, 1)
|
||||
|
||||
notebook.set_cell_metadata(0, 'deletable', 'true') # to perform below test, remove all the cells
|
||||
remove_all_cells(notebook)
|
||||
assert len(notebook.cells) == 1 # notebook should create one automatically on empty notebook
|
|
@ -0,0 +1,65 @@
|
|||
"""Test display of images
|
||||
|
||||
The effect of shape metadata is validated, using Image(retina=True)
|
||||
"""
|
||||
|
||||
from .utils import wait_for_tag
|
||||
|
||||
|
||||
# 2x2 black square in b64 jpeg and png
|
||||
b64_image_data = {
|
||||
"image/png" : b'iVBORw0KGgoAAAANSUhEUgAAAAIAAAACCAIAAAD91JpzAAAAC0lEQVR4nGNgQAYAAA4AAamRc7EA\\nAAAASUVORK5CYII',
|
||||
"image/jpeg" : b'/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0a\nHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIy\nMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCAACAAIDASIA\nAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQA\nAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3\nODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWm\np6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEA\nAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSEx\nBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElK\nU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3\nuLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD5/ooo\noAoo2Qoo'
|
||||
}
|
||||
|
||||
|
||||
def imports(notebook):
|
||||
commands = [
|
||||
'import base64',
|
||||
'from IPython.display import display, Image',
|
||||
]
|
||||
notebook.edit_cell(index=0, content="\n".join(commands))
|
||||
notebook.execute_cell(0)
|
||||
|
||||
|
||||
def validate_img(notebook, cell_index, image_fmt, retina):
|
||||
"""Validate that image renders as expected."""
|
||||
|
||||
b64data = b64_image_data[image_fmt]
|
||||
commands = [
|
||||
'b64data = %s' % b64data,
|
||||
'data = base64.decodebytes(b64data)',
|
||||
'display(Image(data, retina=%s))' % retina
|
||||
]
|
||||
notebook.append("\n".join(commands))
|
||||
notebook.execute_cell(cell_index)
|
||||
|
||||
# Find the image element that was just displayed
|
||||
wait_for_tag(notebook.cells[cell_index], "img", single=True)
|
||||
img_element = notebook.cells[cell_index].find_element_by_tag_name("img")
|
||||
|
||||
src = img_element.get_attribute("src")
|
||||
prefix = src.split(',')[0]
|
||||
expected_prefix = "data:%s;base64" % image_fmt
|
||||
assert prefix == expected_prefix
|
||||
|
||||
expected_size = 1 if retina else 2
|
||||
assert img_element.size["width"] == expected_size
|
||||
assert img_element.size["height"] == expected_size
|
||||
assert img_element.get_attribute("width") == str(expected_size)
|
||||
assert img_element.get_attribute("height") == str(expected_size)
|
||||
|
||||
|
||||
def test_display_image(notebook):
|
||||
imports(notebook)
|
||||
# PNG, non-retina
|
||||
validate_img(notebook, 1, "image/png", False)
|
||||
|
||||
# PNG, retina display
|
||||
validate_img(notebook, 2, "image/png", True)
|
||||
|
||||
# JPEG, non-retina
|
||||
validate_img(notebook, 3, "image/jpeg", False)
|
||||
|
||||
# JPEG, retina display
|
||||
validate_img(notebook, 4, "image/jpeg", True)
|
|
@ -0,0 +1,96 @@
|
|||
"""Test display isolation.
|
||||
|
||||
An object whose metadata contains an "isolated" tag must be isolated
|
||||
from the rest of the document.
|
||||
"""
|
||||
from .utils import wait_for_tag
|
||||
|
||||
|
||||
def test_display_isolation(notebook):
|
||||
import_ln = "from IPython.core.display import HTML, SVG, display, display_svg"
|
||||
notebook.edit_cell(index=0, content=import_ln)
|
||||
notebook.execute_cell(notebook.current_cell)
|
||||
try:
|
||||
isolated_html(notebook)
|
||||
isolated_svg(notebook)
|
||||
finally:
|
||||
# Ensure we switch from iframe back to default content even if test fails
|
||||
notebook.browser.switch_to.default_content()
|
||||
|
||||
|
||||
def isolated_html(notebook):
|
||||
"""Test HTML display isolation.
|
||||
|
||||
HTML styling rendered without isolation will affect the whole
|
||||
document, whereas styling applied with isolation will affect only
|
||||
the local display object.
|
||||
"""
|
||||
red = 'rgb(255, 0, 0)'
|
||||
blue = 'rgb(0, 0, 255)'
|
||||
test_str = "<div id='test'>Should turn red from non-isolation</div>"
|
||||
notebook.add_and_execute_cell(content="display(HTML(%r))" % test_str)
|
||||
non_isolated = (
|
||||
"<style>div{color:%s;}</style>" % red +
|
||||
"<div id='non-isolated'>Should be red</div>")
|
||||
display_ni = "display(HTML(%r), metadata={'isolated':False})" % (
|
||||
non_isolated)
|
||||
notebook.add_and_execute_cell(content=display_ni)
|
||||
isolated = (
|
||||
"<style>div{color:%s;}</style>" % blue +
|
||||
"<div id='isolated'>Should be blue</div>")
|
||||
display_i = "display(HTML(%r), metadata={'isolated':True})" % (
|
||||
isolated)
|
||||
notebook.add_and_execute_cell(content=display_i)
|
||||
|
||||
iframe = wait_for_tag(notebook.browser, "iframe", single=True)
|
||||
|
||||
# The non-isolated div will be in the body
|
||||
non_isolated_div = notebook.body.find_element_by_id("non-isolated")
|
||||
assert non_isolated_div.value_of_css_property("color") == red
|
||||
|
||||
# The non-isolated styling will have affected the output of other cells
|
||||
test_div = notebook.body.find_element_by_id("test")
|
||||
assert test_div.value_of_css_property("color") == red
|
||||
|
||||
# The isolated div will be in an iframe, only that element will be blue
|
||||
notebook.browser.switch_to.frame(iframe)
|
||||
isolated_div = notebook.browser.find_element_by_id("isolated")
|
||||
assert isolated_div.value_of_css_property("color") == blue
|
||||
notebook.browser.switch_to.default_content()
|
||||
# Clean up the html test cells
|
||||
for i in range(1, len(notebook.cells)):
|
||||
notebook.delete_cell(1)
|
||||
|
||||
|
||||
def isolated_svg(notebook):
|
||||
"""Test that multiple isolated SVGs have different scopes.
|
||||
|
||||
Asserts that there no CSS leaks between two isolated SVGs.
|
||||
"""
|
||||
yellow = "rgb(255, 255, 0)"
|
||||
black = "rgb(0, 0, 0)"
|
||||
svg_1_str = """s1 = '''<svg width="1cm" height="1cm" viewBox="0 0 1000 500"><defs><style>rect {fill:%s;}; </style></defs><rect id="r1" x="200" y="100" width="600" height="300" /></svg>'''""" % yellow
|
||||
svg_2_str = """s2 = '''<svg width="1cm" height="1cm" viewBox="0 0 1000 500"><rect id="r2" x="200" y="100" width="600" height="300" /></svg>'''"""
|
||||
|
||||
notebook.add_and_execute_cell(content=svg_1_str)
|
||||
notebook.add_and_execute_cell(content=svg_2_str)
|
||||
notebook.add_and_execute_cell(
|
||||
content="display_svg(SVG(s1), metadata=dict(isolated=True))")
|
||||
notebook.add_and_execute_cell(
|
||||
content="display_svg(SVG(s2), metadata=dict(isolated=True))")
|
||||
iframes = wait_for_tag(notebook.browser, "iframe", wait_for_n=2)
|
||||
|
||||
# The first rectangle will be red
|
||||
notebook.browser.switch_to.frame(iframes[0])
|
||||
isolated_svg_1 = notebook.browser.find_element_by_id('r1')
|
||||
assert isolated_svg_1.value_of_css_property("fill") == yellow
|
||||
notebook.browser.switch_to.default_content()
|
||||
|
||||
# The second rectangle will be black
|
||||
notebook.browser.switch_to.frame(iframes[1])
|
||||
isolated_svg_2 = notebook.browser.find_element_by_id('r2')
|
||||
assert isolated_svg_2.value_of_css_property("fill") == black
|
||||
|
||||
# Clean up the svg test cells
|
||||
for i in range(1, len(notebook.cells)):
|
||||
notebook.delete_cell(1)
|
|
@ -0,0 +1,103 @@
|
|||
"""Tests arrow keys on both command and edit mode"""
|
||||
from selenium.webdriver.common.keys import Keys
|
||||
|
||||
def test_dualmode_arrows(notebook):
|
||||
|
||||
# Tests in command mode.
|
||||
# Setting up the cells to test the keys to move up.
|
||||
notebook.to_command_mode()
|
||||
[notebook.body.send_keys("b") for i in range(3)]
|
||||
|
||||
# Use both "k" and up arrow keys to moving up and enter a value.
|
||||
# Once located on the top cell, use the up arrow keys to prove the top cell is still selected.
|
||||
notebook.body.send_keys("k")
|
||||
notebook.body.send_keys(Keys.ENTER)
|
||||
notebook.body.send_keys("2")
|
||||
notebook.to_command_mode()
|
||||
notebook.body.send_keys(Keys.UP)
|
||||
notebook.body.send_keys(Keys.ENTER)
|
||||
notebook.body.send_keys("1")
|
||||
notebook.to_command_mode()
|
||||
notebook.body.send_keys("k")
|
||||
notebook.body.send_keys(Keys.UP)
|
||||
notebook.body.send_keys(Keys.ENTER)
|
||||
notebook.body.send_keys("0")
|
||||
notebook.to_command_mode()
|
||||
assert notebook.get_cells_contents() == ["0", "1", "2", ""]
|
||||
|
||||
# Use the "k" key on the top cell as well
|
||||
notebook.body.send_keys("k")
|
||||
notebook.body.send_keys(Keys.ENTER)
|
||||
notebook.body.send_keys(" edit #1")
|
||||
notebook.to_command_mode()
|
||||
assert notebook.get_cells_contents() == ["0 edit #1", "1", "2", ""]
|
||||
|
||||
# Setting up the cells to test the keys to move down
|
||||
[notebook.body.send_keys("j") for i in range(3)]
|
||||
[notebook.body.send_keys("a") for i in range(2)]
|
||||
notebook.body.send_keys("k")
|
||||
|
||||
# Use both "j" key and down arrow keys to moving down and enter a value.
|
||||
# Once located on the bottom cell, use the down arrow key to prove the bottom cell is still selected.
|
||||
notebook.body.send_keys(Keys.DOWN)
|
||||
notebook.body.send_keys(Keys.ENTER)
|
||||
notebook.body.send_keys("3")
|
||||
notebook.to_command_mode()
|
||||
notebook.body.send_keys("j")
|
||||
notebook.body.send_keys(Keys.ENTER)
|
||||
notebook.body.send_keys("4")
|
||||
notebook.to_command_mode()
|
||||
notebook.body.send_keys("j")
|
||||
notebook.body.send_keys(Keys.DOWN)
|
||||
notebook.body.send_keys(Keys.ENTER)
|
||||
notebook.body.send_keys("5")
|
||||
notebook.to_command_mode()
|
||||
assert notebook.get_cells_contents() == ["0 edit #1", "1", "2", "3", "4", "5"]
|
||||
|
||||
# Use the "j" key on the top cell as well
|
||||
notebook.body.send_keys("j")
|
||||
notebook.body.send_keys(Keys.ENTER)
|
||||
notebook.body.send_keys(" edit #1")
|
||||
notebook.to_command_mode()
|
||||
assert notebook.get_cells_contents() == ["0 edit #1", "1", "2", "3", "4", "5 edit #1"]
|
||||
|
||||
# On the bottom cell, use both left and right arrow keys to prove the bottom cell is still selected.
|
||||
notebook.body.send_keys(Keys.LEFT)
|
||||
notebook.body.send_keys(Keys.ENTER)
|
||||
notebook.body.send_keys(", #2")
|
||||
notebook.to_command_mode()
|
||||
assert notebook.get_cells_contents() == ["0 edit #1", "1", "2", "3", "4", "5 edit #1, #2"]
|
||||
notebook.body.send_keys(Keys.RIGHT)
|
||||
notebook.body.send_keys(Keys.ENTER)
|
||||
notebook.body.send_keys(" and #3")
|
||||
notebook.to_command_mode()
|
||||
assert notebook.get_cells_contents() == ["0 edit #1", "1", "2", "3", "4", "5 edit #1, #2 and #3"]
|
||||
|
||||
|
||||
# Tests in edit mode.
|
||||
# First, erase the previous content and then setup the cells to test the keys to move up.
|
||||
[notebook.browser.find_element_by_class_name("fa-cut.fa").click() for i in range(6)]
|
||||
[notebook.body.send_keys("b") for i in range(2)]
|
||||
notebook.body.send_keys("a")
|
||||
notebook.body.send_keys(Keys.ENTER)
|
||||
|
||||
# Use the up arrow key to move down and enter a value.
|
||||
# We will use the left arrow key to move one char to the left since moving up on last character only moves selector to the first one.
|
||||
# Once located on the top cell, use the up arrow key to prove the top cell is still selected.
|
||||
notebook.body.send_keys(Keys.UP)
|
||||
notebook.body.send_keys("1")
|
||||
notebook.body.send_keys(Keys.LEFT)
|
||||
[notebook.body.send_keys(Keys.UP) for i in range(2)]
|
||||
notebook.body.send_keys("0")
|
||||
|
||||
# Use the down arrow key to move down and enter a value.
|
||||
# We will use the right arrow key to move one char to the right since moving down puts selector to the last character.
|
||||
# Once located on the bottom cell, use the down arrow key to prove the bottom cell is still selected.
|
||||
notebook.body.send_keys(Keys.DOWN)
|
||||
notebook.body.send_keys(Keys.RIGHT)
|
||||
notebook.body.send_keys(Keys.DOWN)
|
||||
notebook.body.send_keys("2")
|
||||
[notebook.body.send_keys(Keys.DOWN) for i in range(2)]
|
||||
notebook.body.send_keys("3")
|
||||
notebook.to_command_mode()
|
||||
assert notebook.get_cells_contents() == ["0", "1", "2", "3"]
|
|
@ -0,0 +1,58 @@
|
|||
"""Test keyboard shortcuts that change the cell's mode."""
|
||||
|
||||
def test_dualmode_cellmode(notebook):
|
||||
def get_cell_cm_mode(index):
|
||||
code_mirror_mode = notebook.browser.execute_script(
|
||||
"return Jupyter.notebook.get_cell(%s).code_mirror.getMode().name;"%index)
|
||||
return code_mirror_mode
|
||||
|
||||
|
||||
index = 0
|
||||
a = 'hello\nmulti\nline'
|
||||
|
||||
notebook.edit_cell(index=index, content=a)
|
||||
|
||||
"""check for the default cell type"""
|
||||
notebook.to_command_mode()
|
||||
notebook.body.send_keys("r")
|
||||
assert notebook.get_cell_type(index) == 'raw'
|
||||
assert get_cell_cm_mode(index) == 'null'
|
||||
|
||||
"""check cell type after changing to markdown"""
|
||||
notebook.body.send_keys("1")
|
||||
assert notebook.get_cell_type(index) == 'markdown'
|
||||
assert notebook.get_cell_contents(index) == '# ' + a
|
||||
assert get_cell_cm_mode(index) == 'ipythongfm'
|
||||
|
||||
notebook.body.send_keys("2")
|
||||
assert notebook.get_cell_type(index) == 'markdown'
|
||||
assert notebook.get_cell_contents(index) == '## ' + a
|
||||
|
||||
notebook.body.send_keys("3")
|
||||
assert notebook.get_cell_type(index) == 'markdown'
|
||||
assert notebook.get_cell_contents(index) == '### ' + a
|
||||
|
||||
notebook.body.send_keys("4")
|
||||
assert notebook.get_cell_type(index) == 'markdown'
|
||||
assert notebook.get_cell_contents(index) == '#### ' + a
|
||||
|
||||
notebook.body.send_keys("5")
|
||||
assert notebook.get_cell_type(index) == 'markdown'
|
||||
assert notebook.get_cell_contents(index) == '##### ' + a
|
||||
|
||||
notebook.body.send_keys("6")
|
||||
assert notebook.get_cell_type(index) == 'markdown'
|
||||
assert notebook.get_cell_contents(index) == '###### ' + a
|
||||
|
||||
notebook.body.send_keys("m")
|
||||
assert notebook.get_cell_type(index) == 'markdown'
|
||||
assert notebook.get_cell_contents(index) == '###### ' + a
|
||||
|
||||
notebook.body.send_keys("y")
|
||||
assert notebook.get_cell_type(index) == 'code'
|
||||
assert notebook.get_cell_contents(index) == '###### ' + a
|
||||
assert get_cell_cm_mode(index) == 'ipython'
|
||||
|
||||
notebook.body.send_keys("1")
|
||||
assert notebook.get_cell_type(index) == 'markdown'
|
||||
assert notebook.get_cell_contents(index) == '# ' + a
|
|
@ -0,0 +1,54 @@
|
|||
"""Test"""
|
||||
from .utils import shift, validate_dualmode_state
|
||||
|
||||
INITIAL_CELLS = ['', 'print("a")', 'print("b")', 'print("c")']
|
||||
|
||||
def test_dualmode_clipboard(prefill_notebook):
|
||||
notebook = prefill_notebook(INITIAL_CELLS)
|
||||
_, a, b, c = INITIAL_CELLS
|
||||
for i in range(1, 4):
|
||||
notebook.execute_cell(i)
|
||||
|
||||
#Copy/past/cut
|
||||
num_cells = len(notebook.cells)
|
||||
assert notebook.get_cell_contents(1) == a #Cell 1 is a
|
||||
|
||||
notebook.focus_cell(1)
|
||||
notebook.body.send_keys("x") #Cut
|
||||
validate_dualmode_state(notebook, 'command', 1)
|
||||
assert notebook.get_cell_contents(1) == b #Cell 2 is now where cell 1 was
|
||||
assert len(notebook.cells) == num_cells-1 #A cell was removed
|
||||
|
||||
notebook.focus_cell(2)
|
||||
notebook.body.send_keys("v") #Paste
|
||||
validate_dualmode_state(notebook, 'command', 3)
|
||||
assert notebook.get_cell_contents(3) == a #Cell 3 has the cut contents
|
||||
assert len(notebook.cells) == num_cells #A cell was added
|
||||
|
||||
notebook.body.send_keys("v") #Paste
|
||||
validate_dualmode_state(notebook, 'command', 4)
|
||||
assert notebook.get_cell_contents(4) == a #Cell a has the cut contents
|
||||
assert len(notebook.cells) == num_cells+1 #A cell was added
|
||||
|
||||
notebook.focus_cell(1)
|
||||
notebook.body.send_keys("c") #Copy
|
||||
validate_dualmode_state(notebook, 'command', 1)
|
||||
assert notebook.get_cell_contents(1) == b #Cell 1 is b
|
||||
|
||||
notebook.focus_cell(2)
|
||||
notebook.body.send_keys("c") #Copy
|
||||
validate_dualmode_state(notebook, 'command', 2)
|
||||
assert notebook.get_cell_contents(2) == c #Cell 2 is c
|
||||
|
||||
notebook.focus_cell(4)
|
||||
notebook.body.send_keys("v") #Paste
|
||||
validate_dualmode_state(notebook, 'command', 5)
|
||||
assert notebook.get_cell_contents(2) == c #Cell 2 has the copied contents
|
||||
assert notebook.get_cell_contents(5) == c #Cell 5 has the copied contents
|
||||
assert len(notebook.cells) == num_cells+2 #A cell was added
|
||||
|
||||
notebook.focus_cell(0)
|
||||
shift(notebook.browser, 'v') #Paste
|
||||
validate_dualmode_state(notebook, 'command', 0)
|
||||
assert notebook.get_cell_contents(0) == c #Cell 0 has the copied contents
|
||||
assert len(notebook.cells) == num_cells+3 #A cell was added
|
|
@ -0,0 +1,74 @@
|
|||
''' Test keyboard invoked execution '''
|
||||
|
||||
from selenium.webdriver.common.keys import Keys
|
||||
|
||||
from .utils import shift, cmdtrl, alt, validate_dualmode_state
|
||||
|
||||
INITIAL_CELLS = ['', 'print("a")', 'print("b")', 'print("c")']
|
||||
|
||||
def test_dualmode_execute(prefill_notebook):
|
||||
notebook = prefill_notebook(INITIAL_CELLS)
|
||||
for i in range(1, 4):
|
||||
notebook.execute_cell(i)
|
||||
|
||||
#shift-enter
|
||||
#last cell in notebook
|
||||
base_index = 3
|
||||
notebook.focus_cell(base_index)
|
||||
shift(notebook.browser, Keys.ENTER) #creates one cell
|
||||
validate_dualmode_state(notebook, 'edit', base_index + 1)
|
||||
|
||||
#Not last cell in notebook & starts in edit mode
|
||||
notebook.focus_cell(base_index)
|
||||
notebook.body.send_keys(Keys.ENTER) #Enter edit mode
|
||||
validate_dualmode_state(notebook, 'edit', base_index)
|
||||
shift(notebook.browser, Keys.ENTER) #creates one cell
|
||||
validate_dualmode_state(notebook, 'command', base_index + 1)
|
||||
|
||||
#Starts in command mode
|
||||
notebook.body.send_keys('k')
|
||||
validate_dualmode_state(notebook, 'command', base_index)
|
||||
shift(notebook.browser, Keys.ENTER) #creates one cell
|
||||
validate_dualmode_state(notebook, 'command', base_index + 1)
|
||||
|
||||
|
||||
#Ctrl-enter
|
||||
#Last cell in notebook
|
||||
base_index += 1
|
||||
cmdtrl(notebook.browser, Keys.ENTER)
|
||||
validate_dualmode_state(notebook, 'command', base_index)
|
||||
|
||||
#Not last cell in notebook & stats in edit mode
|
||||
notebook.focus_cell(base_index - 1)
|
||||
notebook.body.send_keys(Keys.ENTER) #Enter edit mode
|
||||
validate_dualmode_state(notebook, 'edit', base_index - 1)
|
||||
cmdtrl(notebook.browser, Keys.ENTER)
|
||||
|
||||
#Starts in command mode
|
||||
notebook.body.send_keys('j')
|
||||
validate_dualmode_state(notebook, 'command', base_index)
|
||||
cmdtrl(notebook.browser, Keys.ENTER)
|
||||
validate_dualmode_state(notebook, 'command', base_index)
|
||||
|
||||
|
||||
#Alt-enter
|
||||
#Last cell in notebook
|
||||
alt(notebook.browser, Keys.ENTER)
|
||||
validate_dualmode_state(notebook, 'edit', base_index + 1)
|
||||
#Not last cell in notebook &starts in edit mode
|
||||
notebook.focus_cell(base_index)
|
||||
notebook.body.send_keys(Keys.ENTER) #Enter edit mode
|
||||
validate_dualmode_state(notebook, 'edit', base_index)
|
||||
alt(notebook.browser, Keys.ENTER)
|
||||
validate_dualmode_state(notebook, 'edit', base_index + 1)
|
||||
#starts in command mode
|
||||
notebook.body.send_keys(Keys.ESCAPE, 'k')
|
||||
validate_dualmode_state(notebook, 'command', base_index)
|
||||
alt(notebook.browser, Keys.ENTER)
|
||||
validate_dualmode_state(notebook, 'edit', base_index + 1)
|
||||
|
||||
|
||||
#Notebook will now have 8 cells, the index of the last cell will be 7
|
||||
assert len(notebook) == 8 #Cells where added
|
||||
notebook.focus_cell(7)
|
||||
validate_dualmode_state(notebook, 'command', 7)
|
|
@ -0,0 +1,51 @@
|
|||
from selenium.webdriver.common.keys import Keys
|
||||
from .utils import shift
|
||||
|
||||
INITIAL_CELLS = ['print("a")', 'print("b")', 'print("c")']
|
||||
|
||||
def test_insert_cell(prefill_notebook):
|
||||
notebook = prefill_notebook(INITIAL_CELLS)
|
||||
|
||||
notebook.to_command_mode()
|
||||
notebook.focus_cell(2)
|
||||
notebook.convert_cell_type(2, "markdown")
|
||||
|
||||
# insert code cell above
|
||||
notebook.current_cell.send_keys("a")
|
||||
assert notebook.get_cell_contents(2) == ""
|
||||
assert notebook.get_cell_type(2) == "code"
|
||||
assert len(notebook.cells) == 4
|
||||
|
||||
# insert code cell below
|
||||
notebook.current_cell.send_keys("b")
|
||||
assert notebook.get_cell_contents(2) == ""
|
||||
assert notebook.get_cell_contents(3) == ""
|
||||
assert notebook.get_cell_type(3) == "code"
|
||||
assert len(notebook.cells) == 5
|
||||
|
||||
notebook.edit_cell(index=1, content="cell1")
|
||||
notebook.focus_cell(1)
|
||||
notebook.current_cell.send_keys("a")
|
||||
assert notebook.get_cell_contents(1) == ""
|
||||
assert notebook.get_cell_contents(2) == "cell1"
|
||||
|
||||
notebook.edit_cell(index=1, content='cell1')
|
||||
notebook.edit_cell(index=2, content='cell2')
|
||||
notebook.edit_cell(index=3, content='cell3')
|
||||
notebook.focus_cell(2)
|
||||
notebook.current_cell.send_keys("b")
|
||||
assert notebook.get_cell_contents(1) == "cell1"
|
||||
assert notebook.get_cell_contents(2) == "cell2"
|
||||
assert notebook.get_cell_contents(3) == ""
|
||||
assert notebook.get_cell_contents(4) == "cell3"
|
||||
|
||||
# insert above multiple selected cells
|
||||
notebook.focus_cell(1)
|
||||
shift(notebook.browser, Keys.DOWN)
|
||||
notebook.current_cell.send_keys('a')
|
||||
|
||||
# insert below multiple selected cells
|
||||
notebook.focus_cell(2)
|
||||
shift(notebook.browser, Keys.DOWN)
|
||||
notebook.current_cell.send_keys('b')
|
||||
assert notebook.get_cells_contents()[1:5] == ["", "cell1", "cell2", ""]
|
|
@ -0,0 +1,53 @@
|
|||
'''Test'''
|
||||
|
||||
from selenium.webdriver.common.keys import Keys
|
||||
|
||||
from .utils import cmdtrl, shift, validate_dualmode_state
|
||||
|
||||
def test_dualmode_markdown(notebook):
|
||||
def is_cell_rendered(index):
|
||||
JS = 'return !!IPython.notebook.get_cell(%s).rendered;'%index
|
||||
return notebook.browser.execute_script(JS)
|
||||
|
||||
|
||||
a = 'print("a")'
|
||||
index = 1
|
||||
notebook.append(a)
|
||||
|
||||
#Markdown rendering / unrendering
|
||||
notebook.focus_cell(index)
|
||||
validate_dualmode_state(notebook, 'command', index)
|
||||
notebook.body.send_keys("m")
|
||||
assert notebook.get_cell_type(index) == 'markdown'
|
||||
assert not is_cell_rendered(index) #cell is not rendered
|
||||
|
||||
notebook.body.send_keys(Keys.ENTER)#cell is unrendered
|
||||
assert not is_cell_rendered(index) #cell is not rendered
|
||||
validate_dualmode_state(notebook, 'edit', index)
|
||||
|
||||
cmdtrl(notebook.browser, Keys.ENTER)
|
||||
assert is_cell_rendered(index) #cell is rendered with crtl+enter
|
||||
validate_dualmode_state(notebook, 'command', index)
|
||||
|
||||
notebook.body.send_keys(Keys.ENTER)#cell is unrendered
|
||||
assert not is_cell_rendered(index) #cell is not rendered
|
||||
|
||||
notebook.focus_cell(index - 1)
|
||||
assert not is_cell_rendered(index) #Select index-1; cell index is still not rendered
|
||||
validate_dualmode_state(notebook, 'command', index - 1)
|
||||
|
||||
notebook.focus_cell(index)
|
||||
validate_dualmode_state(notebook, 'command', index)
|
||||
cmdtrl(notebook.browser, Keys.ENTER)
|
||||
assert is_cell_rendered(index)#Cell is rendered
|
||||
|
||||
notebook.focus_cell(index - 1)
|
||||
validate_dualmode_state(notebook, 'command', index - 1)
|
||||
|
||||
shift(notebook.browser, Keys.ENTER)
|
||||
validate_dualmode_state(notebook, 'command', index)
|
||||
assert is_cell_rendered(index)#Cell is rendered
|
||||
|
||||
shift(notebook.browser, Keys.ENTER)
|
||||
validate_dualmode_state(notebook, 'edit', index + 1)
|
||||
assert is_cell_rendered(index)#Cell is rendered
|
|
@ -0,0 +1,66 @@
|
|||
from selenium.webdriver.common.keys import Keys
|
||||
from .utils import shift, cmdtrl
|
||||
|
||||
|
||||
def test_execute_code(notebook):
|
||||
browser = notebook.browser
|
||||
|
||||
def clear_outputs():
|
||||
return notebook.browser.execute_script(
|
||||
"Jupyter.notebook.clear_all_output();")
|
||||
|
||||
# Execute cell with Javascript API
|
||||
notebook.edit_cell(index=0, content='a=10; print(a)')
|
||||
browser.execute_script("Jupyter.notebook.get_cell(0).execute();")
|
||||
outputs = notebook.wait_for_cell_output(0)
|
||||
assert outputs[0].text == '10'
|
||||
|
||||
# Execute cell with Shift-Enter
|
||||
notebook.edit_cell(index=0, content='a=11; print(a)')
|
||||
clear_outputs()
|
||||
shift(notebook.browser, Keys.ENTER)
|
||||
outputs = notebook.wait_for_cell_output(0)
|
||||
assert outputs[0].text == '11'
|
||||
notebook.delete_cell(index=1)
|
||||
|
||||
# Execute cell with Ctrl-Enter
|
||||
notebook.edit_cell(index=0, content='a=12; print(a)')
|
||||
clear_outputs()
|
||||
cmdtrl(notebook.browser, Keys.ENTER)
|
||||
outputs = notebook.wait_for_cell_output(0)
|
||||
assert outputs[0].text == '12'
|
||||
|
||||
# Execute cell with toolbar button
|
||||
notebook.edit_cell(index=0, content='a=13; print(a)')
|
||||
clear_outputs()
|
||||
notebook.browser.find_element_by_css_selector(
|
||||
"button[data-jupyter-action='jupyter-notebook:run-cell-and-select-next']").click()
|
||||
outputs = notebook.wait_for_cell_output(0)
|
||||
assert outputs[0].text == '13'
|
||||
|
||||
# Set up two cells to test stopping on error
|
||||
notebook.edit_cell(index=0, content='raise IOError')
|
||||
notebook.edit_cell(index=1, content='a=14; print(a)')
|
||||
|
||||
# Default behaviour: stop on error
|
||||
clear_outputs()
|
||||
browser.execute_script("""
|
||||
var cell0 = Jupyter.notebook.get_cell(0);
|
||||
var cell1 = Jupyter.notebook.get_cell(1);
|
||||
cell0.execute();
|
||||
cell1.execute();
|
||||
""")
|
||||
outputs = notebook.wait_for_cell_output(0)
|
||||
assert notebook.get_cell_output(1) == []
|
||||
|
||||
# Execute a cell with stop_on_error=false
|
||||
clear_outputs()
|
||||
browser.execute_script("""
|
||||
var cell0 = Jupyter.notebook.get_cell(0);
|
||||
var cell1 = Jupyter.notebook.get_cell(1);
|
||||
cell0.execute(false);
|
||||
cell1.execute();
|
||||
""")
|
||||
outputs = notebook.wait_for_cell_output(1)
|
||||
assert outputs[0].text == '14'
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
INITIAL_CELLS = ["hello", "hellohello", "abc", "ello"]
|
||||
|
||||
def test_find_and_replace(prefill_notebook):
|
||||
""" test find and replace on all the cells """
|
||||
notebook = prefill_notebook(INITIAL_CELLS)
|
||||
|
||||
find_str = "ello"
|
||||
replace_str = "foo"
|
||||
|
||||
# replace the strings
|
||||
notebook.find_and_replace(index=0, find_txt=find_str, replace_txt=replace_str)
|
||||
|
||||
# check content of the cells
|
||||
assert notebook.get_cells_contents() == [
|
||||
s.replace(find_str, replace_str) for s in INITIAL_CELLS
|
||||
]
|
|
@ -0,0 +1,36 @@
|
|||
from .utils import wait_for_selector
|
||||
|
||||
def interrupt_from_menu(notebook):
|
||||
# Click interrupt button in kernel menu
|
||||
notebook.browser.find_element_by_id('kernellink').click()
|
||||
wait_for_selector(notebook.browser, '#int_kernel', single=True).click()
|
||||
|
||||
def interrupt_from_keyboard(notebook):
|
||||
notebook.body.send_keys("ii")
|
||||
|
||||
|
||||
def test_interrupt(notebook):
|
||||
""" Test the interrupt function using both the button in the Kernel menu and the keyboard shortcut "ii"
|
||||
|
||||
Having trouble accessing the Interrupt message when execution is halted. I am assuming that the
|
||||
message does not lie in the "outputs" field of the cell's JSON object. Using a timeout work-around for
|
||||
test with an infinite loop. We know the interrupt function is working if this test passes.
|
||||
Hope this is a good start.
|
||||
"""
|
||||
|
||||
text = ('import time\n'
|
||||
'for x in range(3):\n'
|
||||
' time.sleep(1)')
|
||||
|
||||
notebook.edit_cell(index=0, content=text)
|
||||
|
||||
for interrupt_method in (interrupt_from_menu, interrupt_from_keyboard):
|
||||
notebook.clear_cell_output(0)
|
||||
notebook.to_command_mode()
|
||||
notebook.execute_cell(0)
|
||||
|
||||
interrupt_method(notebook)
|
||||
|
||||
# Wait for an output to appear
|
||||
output = wait_for_selector(notebook.browser, '.output_subarea', single=True)
|
||||
assert 'KeyboardInterrupt' in output.text
|
|
@ -0,0 +1,60 @@
|
|||
from selenium.common.exceptions import TimeoutException
|
||||
from selenium.webdriver.common.by import By
|
||||
from selenium.webdriver.support import expected_conditions as EC
|
||||
from selenium.webdriver.support.ui import WebDriverWait
|
||||
from notebook.tests.selenium.utils import wait_for_selector
|
||||
|
||||
restart_selectors = [
|
||||
'#restart_kernel', '#restart_clear_output', '#restart_run_all'
|
||||
]
|
||||
notify_interaction = '#notification_kernel > span'
|
||||
|
||||
shutdown_selector = '#shutdown_kernel'
|
||||
confirm_selector = '.btn-danger'
|
||||
cancel_selector = ".modal-footer button:first-of-type"
|
||||
|
||||
|
||||
def test_cancel_restart_or_shutdown(notebook):
|
||||
"""Click each of the restart options, then cancel the confirmation dialog"""
|
||||
browser = notebook.browser
|
||||
kernel_menu = browser.find_element_by_id('kernellink')
|
||||
|
||||
for menu_item in restart_selectors + [shutdown_selector]:
|
||||
kernel_menu.click()
|
||||
wait_for_selector(browser, menu_item, visible=True, single=True).click()
|
||||
wait_for_selector(browser, cancel_selector, visible=True, single=True).click()
|
||||
WebDriverWait(browser, 3).until(
|
||||
EC.invisibility_of_element((By.CSS_SELECTOR, '.modal-backdrop'))
|
||||
)
|
||||
assert notebook.is_kernel_running()
|
||||
|
||||
|
||||
def test_menu_items(notebook):
|
||||
browser = notebook.browser
|
||||
kernel_menu = browser.find_element_by_id('kernellink')
|
||||
|
||||
for menu_item in restart_selectors:
|
||||
# Shutdown
|
||||
kernel_menu.click()
|
||||
wait_for_selector(browser, shutdown_selector, visible=True, single=True).click()
|
||||
|
||||
# Confirm shutdown
|
||||
wait_for_selector(browser, confirm_selector, visible=True, single=True).click()
|
||||
|
||||
WebDriverWait(browser, 3).until(
|
||||
lambda b: not notebook.is_kernel_running(),
|
||||
message="Kernel did not shut down as expected"
|
||||
)
|
||||
|
||||
# Restart
|
||||
# Selenium can't click the menu while a modal dialog is fading out
|
||||
WebDriverWait(browser, 3).until(
|
||||
EC.invisibility_of_element((By.CSS_SELECTOR, '.modal-backdrop'))
|
||||
)
|
||||
kernel_menu.click()
|
||||
|
||||
wait_for_selector(browser, menu_item, visible=True, single=True).click()
|
||||
WebDriverWait(browser, 10).until(
|
||||
lambda b: notebook.is_kernel_running(),
|
||||
message="Restart (%r) after shutdown did not start kernel" % menu_item
|
||||
)
|
|
@ -0,0 +1,41 @@
|
|||
from nbformat.v4 import new_markdown_cell
|
||||
|
||||
def get_rendered_contents(nb):
|
||||
cl = ["text_cell", "render"]
|
||||
rendered_cells = [cell.find_element_by_class_name("text_cell_render")
|
||||
for cell in nb.cells
|
||||
if all([c in cell.get_attribute("class") for c in cl])]
|
||||
return [x.get_attribute('innerHTML').strip()
|
||||
for x in rendered_cells
|
||||
if x is not None]
|
||||
|
||||
|
||||
def test_markdown_cell(prefill_notebook):
|
||||
nb = prefill_notebook([new_markdown_cell(md) for md in [
|
||||
'# Foo', '**Bar**', '*Baz*', '```\nx = 1\n```', '```aaaa\nx = 1\n```',
|
||||
'```python\ns = "$"\nt = "$"\n```'
|
||||
]])
|
||||
|
||||
assert get_rendered_contents(nb) == [
|
||||
'<h1 id="Foo">Foo<a class="anchor-link" href="#Foo">¶</a></h1>',
|
||||
'<p><strong>Bar</strong></p>',
|
||||
'<p><em>Baz</em></p>',
|
||||
'<pre><code>x = 1</code></pre>',
|
||||
'<pre><code class="cm-s-ipython language-aaaa">x = 1</code></pre>',
|
||||
'<pre><code class="cm-s-ipython language-python">' +
|
||||
'<span class="cm-variable">s</span> <span class="cm-operator">=</span> <span class="cm-string">"$"</span>\n' +
|
||||
'<span class="cm-variable">t</span> <span class="cm-operator">=</span> <span class="cm-string">"$"</span></code></pre>'
|
||||
]
|
||||
|
||||
def test_markdown_headings(notebook):
|
||||
lst = list([1, 2, 3, 4, 5, 6, 2, 1])
|
||||
for i in lst:
|
||||
notebook.add_markdown_cell()
|
||||
cell_text = notebook.browser.execute_script(f"""
|
||||
var cell = IPython.notebook.get_cell(1);
|
||||
cell.set_heading_level({i});
|
||||
cell.get_text();
|
||||
""")
|
||||
assert notebook.get_cell_contents(1) == "#" * i + " "
|
||||
notebook.delete_cell(1)
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
"""Tests the merge cell api."""
|
||||
|
||||
INITIAL_CELLS = [
|
||||
"foo = 5",
|
||||
"bar = 10",
|
||||
"baz = 15",
|
||||
"print(foo)",
|
||||
"print(bar)",
|
||||
"print(baz)",
|
||||
]
|
||||
|
||||
def test_merge_cells(prefill_notebook):
|
||||
notebook = prefill_notebook(INITIAL_CELLS)
|
||||
a, b, c, d, e, f = INITIAL_CELLS
|
||||
|
||||
# Before merging, there are 6 separate cells
|
||||
assert notebook.get_cells_contents() == [a, b, c, d, e, f]
|
||||
|
||||
# Focus on the second cell and merge it with the cell above
|
||||
notebook.focus_cell(1)
|
||||
notebook.browser.execute_script("Jupyter.notebook.merge_cell_above();")
|
||||
merged_a_b = "%s\n\n%s" % (a, b)
|
||||
assert notebook.get_cells_contents() == [merged_a_b, c, d, e, f]
|
||||
|
||||
# Focus on the second cell and merge it with the cell below
|
||||
notebook.focus_cell(1)
|
||||
notebook.browser.execute_script("Jupyter.notebook.merge_cell_below();")
|
||||
merged_c_d = "%s\n\n%s" % (c, d)
|
||||
assert notebook.get_cells_contents() == [merged_a_b, merged_c_d, e, f]
|
||||
|
||||
# Merge everything down to a single cell with selected cells
|
||||
notebook.select_cell_range(0,3)
|
||||
notebook.browser.execute_script("Jupyter.notebook.merge_selected_cells();")
|
||||
merged_all = "%s\n\n%s\n\n%s\n\n%s" % (merged_a_b, merged_c_d, e, f)
|
||||
assert notebook.get_cells_contents() == [merged_all]
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
INITIAL_CELLS = ['1', '2', '3', '4', '5', '6']
|
||||
def test_move_multiselection(prefill_notebook):
|
||||
notebook = prefill_notebook(INITIAL_CELLS)
|
||||
def assert_oder(pre_message, expected_state):
|
||||
for i in range(len(expected_state)):
|
||||
assert expected_state[i] == notebook.get_cell_contents(i), f"{pre_message}: Verify that cell {i} has for content: {expected_state[i]} found: {notebook.get_cell_contents(i)}"
|
||||
|
||||
# Select 3 first cells
|
||||
notebook.select_cell_range(0, 2)
|
||||
notebook.browser.execute_script(
|
||||
"Jupyter.notebook.move_selection_up();"
|
||||
)
|
||||
# Should not move up at top
|
||||
assert_oder('move up at top', ['1', '2', '3', '4', '5','6'])
|
||||
|
||||
# We do not need to reselect, move/up down should keep the selection.
|
||||
notebook.browser.execute_script(
|
||||
"Jupyter.notebook.move_selection_down();"
|
||||
)
|
||||
notebook.browser.execute_script(
|
||||
"Jupyter.notebook.move_selection_down();"
|
||||
)
|
||||
notebook.browser.execute_script(
|
||||
"Jupyter.notebook.move_selection_down();"
|
||||
)
|
||||
|
||||
# 3 times down should move the 3 selected cells to the bottom
|
||||
assert_oder("move down to bottom", ['4', '5', '6', '1', '2', '3'])
|
||||
notebook.browser.execute_script(
|
||||
"Jupyter.notebook.move_selection_down();"
|
||||
)
|
||||
|
||||
# They can't go any futher
|
||||
assert_oder("move down to bottom", ['4', '5', '6', '1', '2', '3'])
|
||||
|
||||
notebook.browser.execute_script(
|
||||
"Jupyter.notebook.move_selection_up();"
|
||||
)
|
||||
notebook.browser.execute_script(
|
||||
"Jupyter.notebook.move_selection_up();"
|
||||
)
|
||||
notebook.browser.execute_script(
|
||||
"Jupyter.notebook.move_selection_up();"
|
||||
)
|
||||
|
||||
# Bring them back on top
|
||||
assert_oder('move up at top', ['1', '2', '3', '4', '5','6'])
|
|
@ -0,0 +1,63 @@
|
|||
INITIAL_CELLS = ['print("a")', 'print("b")', 'print("c")']
|
||||
|
||||
def test_multiselect(prefill_notebook):
|
||||
notebook = prefill_notebook(INITIAL_CELLS)
|
||||
|
||||
def extend_selection_by(delta):
|
||||
notebook.browser.execute_script(
|
||||
"Jupyter.notebook.extend_selection_by(arguments[0]);", delta)
|
||||
|
||||
def n_selected_cells():
|
||||
return notebook.browser.execute_script(
|
||||
"return Jupyter.notebook.get_selected_cells().length;")
|
||||
|
||||
notebook.focus_cell(0)
|
||||
assert n_selected_cells() == 1
|
||||
|
||||
# Check that only one cell is selected according to CSS classes as well
|
||||
selected_css = notebook.browser.find_elements_by_css_selector(
|
||||
'.cell.jupyter-soft-selected, .cell.selected')
|
||||
assert len(selected_css) == 1
|
||||
|
||||
# Extend the selection down one
|
||||
extend_selection_by(1)
|
||||
assert n_selected_cells() == 2
|
||||
|
||||
# Contract the selection up one
|
||||
extend_selection_by(-1)
|
||||
assert n_selected_cells() == 1
|
||||
|
||||
# Extend the selection up one
|
||||
notebook.focus_cell(1)
|
||||
extend_selection_by(-1)
|
||||
assert n_selected_cells() == 2
|
||||
|
||||
# Convert selected cells to Markdown
|
||||
notebook.browser.execute_script("Jupyter.notebook.cells_to_markdown();")
|
||||
cell_types = notebook.browser.execute_script(
|
||||
"return Jupyter.notebook.get_cells().map(c => c.cell_type)")
|
||||
assert cell_types == ['markdown', 'markdown', 'code']
|
||||
# One cell left selected after conversion
|
||||
assert n_selected_cells() == 1
|
||||
|
||||
# Convert selected cells to raw
|
||||
notebook.focus_cell(1)
|
||||
extend_selection_by(1)
|
||||
assert n_selected_cells() == 2
|
||||
notebook.browser.execute_script("Jupyter.notebook.cells_to_raw();")
|
||||
cell_types = notebook.browser.execute_script(
|
||||
"return Jupyter.notebook.get_cells().map(c => c.cell_type)")
|
||||
assert cell_types == ['markdown', 'raw', 'raw']
|
||||
# One cell left selected after conversion
|
||||
assert n_selected_cells() == 1
|
||||
|
||||
# Convert selected cells to code
|
||||
notebook.focus_cell(0)
|
||||
extend_selection_by(2)
|
||||
assert n_selected_cells() == 3
|
||||
notebook.browser.execute_script("Jupyter.notebook.cells_to_code();")
|
||||
cell_types = notebook.browser.execute_script(
|
||||
"return Jupyter.notebook.get_cells().map(c => c.cell_type)")
|
||||
assert cell_types == ['code'] * 3
|
||||
# One cell left selected after conversion
|
||||
assert n_selected_cells() == 1
|
|
@ -0,0 +1,44 @@
|
|||
|
||||
INITIAL_CELLS = ['print("a")', 'print("b")', 'print("c")']
|
||||
def test_multiselect_toggle(prefill_notebook):
|
||||
notebook = prefill_notebook(INITIAL_CELLS)
|
||||
def extend_selection_by(delta):
|
||||
notebook.browser.execute_script(
|
||||
"Jupyter.notebook.extend_selection_by(arguments[0]);", delta)
|
||||
|
||||
def n_selected_cells():
|
||||
return notebook.browser.execute_script(
|
||||
"return Jupyter.notebook.get_selected_cells().length;")
|
||||
|
||||
def select_cells():
|
||||
notebook.focus_cell(0)
|
||||
extend_selection_by(2)
|
||||
|
||||
# Test that cells, which start off not collapsed, are collapsed after
|
||||
# calling the multiselected cell toggle.
|
||||
select_cells()
|
||||
assert n_selected_cells() == 3
|
||||
notebook.browser.execute_script("Jupyter.notebook.execute_selected_cells();")
|
||||
select_cells()
|
||||
notebook.browser.execute_script("Jupyter.notebook.toggle_cells_outputs();")
|
||||
cell_output_states = notebook.browser.execute_script(
|
||||
"return Jupyter.notebook.get_cells().map(c => c.collapsed)")
|
||||
assert cell_output_states == [False] * 3, "ensure that all cells are not collapsed"
|
||||
|
||||
# Test that cells, which start off not scrolled are scrolled after
|
||||
# calling the multiselected scroll toggle.
|
||||
select_cells()
|
||||
assert n_selected_cells() == 3
|
||||
notebook.browser.execute_script("Jupyter.notebook.toggle_cells_outputs_scroll();")
|
||||
cell_scrolled_states = notebook.browser.execute_script(
|
||||
"return Jupyter.notebook.get_cells().map(c => c.output_area.scroll_state)")
|
||||
assert all(cell_scrolled_states), "ensure that all have scrolling enabled"
|
||||
|
||||
# Test that cells, which start off not cleared are cleared after
|
||||
# calling the multiselected scroll toggle.
|
||||
select_cells()
|
||||
assert n_selected_cells() == 3
|
||||
notebook.browser.execute_script("Jupyter.notebook.clear_cells_outputs();")
|
||||
cell_outputs_cleared = notebook.browser.execute_script(
|
||||
"return Jupyter.notebook.get_cells().map(c => c.output_area.element.html())")
|
||||
assert cell_outputs_cleared == [""] * 3, "ensure that all cells are cleared"
|
|
@ -0,0 +1,103 @@
|
|||
"""
|
||||
Test the notification area and widgets
|
||||
"""
|
||||
import pytest
|
||||
|
||||
from .utils import wait_for_selector, wait_for_script_to_return_true
|
||||
|
||||
|
||||
def get_widget(notebook, name):
|
||||
return notebook.browser.execute_script(
|
||||
f"return IPython.notification_area.get_widget('{name}') !== undefined"
|
||||
)
|
||||
|
||||
|
||||
def widget(notebook, name):
|
||||
return notebook.browser.execute_script(
|
||||
f"return IPython.notification_area.widget('{name}') !== undefined"
|
||||
)
|
||||
|
||||
|
||||
def new_notification_widget(notebook, name):
|
||||
return notebook.browser.execute_script(
|
||||
f"return IPython.notification_area.new_notification_widget('{name}') !== undefined"
|
||||
)
|
||||
|
||||
|
||||
def widget_has_class(notebook, name, class_name):
|
||||
return notebook.browser.execute_script(
|
||||
f"""
|
||||
var w = IPython.notification_area.get_widget('{name}');
|
||||
return w.element.hasClass('{class_name}');
|
||||
"""
|
||||
)
|
||||
|
||||
|
||||
def widget_message(notebook, name):
|
||||
return notebook.browser.execute_script(
|
||||
f"""
|
||||
var w = IPython.notification_area.get_widget('{name}');
|
||||
return w.get_message();
|
||||
"""
|
||||
)
|
||||
|
||||
|
||||
def test_notification(notebook):
|
||||
# check that existing widgets are there
|
||||
assert get_widget(notebook, "kernel") and widget(notebook, "kernel"),\
|
||||
"The kernel notification widget exists"
|
||||
assert get_widget(notebook, "notebook") and widget(notebook, "notebook"),\
|
||||
"The notebook notification widget exists"
|
||||
|
||||
# try getting a non-existent widget
|
||||
with pytest.raises(Exception):
|
||||
get_widget(notebook, "foo")
|
||||
|
||||
# try creating a non-existent widget
|
||||
assert widget(notebook, "bar"), "widget: new widget is created"
|
||||
|
||||
# try creating a widget that already exists
|
||||
with pytest.raises(Exception):
|
||||
new_notification_widget(notebook, "kernel")
|
||||
|
||||
# test creating 'info', 'warning' and 'danger' messages
|
||||
for level in ("info", "warning", "danger"):
|
||||
notebook.browser.execute_script(f"""
|
||||
var tnw = IPython.notification_area.widget('test');
|
||||
tnw.{level}('test {level}');
|
||||
""")
|
||||
wait_for_selector(notebook.browser, "#notification_test", visible=True)
|
||||
|
||||
assert widget_has_class(notebook, "test", level), f"{level}: class is correct"
|
||||
assert widget_message(notebook, "test") == f"test {level}", f"{level}: message is correct"
|
||||
|
||||
# test message timeout
|
||||
notebook.browser.execute_script("""
|
||||
var tnw = IPython.notification_area.widget('test');
|
||||
tnw.set_message('test timeout', 1000);
|
||||
""")
|
||||
wait_for_selector(notebook.browser, "#notification_test", visible=True)
|
||||
|
||||
assert widget_message(notebook, "test") == "test timeout", "timeout: message is correct"
|
||||
wait_for_selector(notebook.browser, "#notification_test", obscures=True)
|
||||
assert widget_message(notebook, "test") == "", "timeout: message was cleared"
|
||||
|
||||
# test click callback
|
||||
notebook.browser.execute_script("""
|
||||
var tnw = IPython.notification_area.widget('test');
|
||||
tnw._clicked = false;
|
||||
tnw.set_message('test click', undefined, function () {
|
||||
tnw._clicked = true;
|
||||
return true;
|
||||
});
|
||||
""")
|
||||
wait_for_selector(notebook.browser, "#notification_test", visible=True)
|
||||
|
||||
assert widget_message(notebook, "test") == "test click", "callback: message is correct"
|
||||
|
||||
notebook.browser.find_element_by_id("notification_test").click()
|
||||
wait_for_script_to_return_true(notebook.browser,
|
||||
'return IPython.notification_area.widget("test")._clicked;')
|
||||
wait_for_selector(notebook.browser, "#notification_test", obscures=True)
|
||||
|
||||
assert widget_message(notebook, "test") == "", "callback: message was cleared"
|
|
@ -0,0 +1,30 @@
|
|||
|
||||
def test_prompt_numbers(prefill_notebook):
|
||||
notebook = prefill_notebook(['print("a")'])
|
||||
|
||||
def get_prompt():
|
||||
return (
|
||||
notebook.cells[0].find_element_by_class_name('input')
|
||||
.find_element_by_class_name('input_prompt')
|
||||
.get_attribute('innerHTML').strip()
|
||||
)
|
||||
|
||||
def set_prompt(value):
|
||||
notebook.set_cell_input_prompt(0, value)
|
||||
|
||||
assert get_prompt() == "<bdi>In</bdi> [ ]:"
|
||||
|
||||
set_prompt(2)
|
||||
assert get_prompt() == "<bdi>In</bdi> [2]:"
|
||||
|
||||
set_prompt(0)
|
||||
assert get_prompt() == "<bdi>In</bdi> [0]:"
|
||||
|
||||
set_prompt("'*'")
|
||||
assert get_prompt() == "<bdi>In</bdi> [*]:"
|
||||
|
||||
set_prompt("undefined")
|
||||
assert get_prompt() == "<bdi>In</bdi> [ ]:"
|
||||
|
||||
set_prompt("null")
|
||||
assert get_prompt() == "<bdi>In</bdi> [ ]:"
|
65
venv/Lib/site-packages/notebook/tests/selenium/test_save.py
Normal file
65
venv/Lib/site-packages/notebook/tests/selenium/test_save.py
Normal file
|
@ -0,0 +1,65 @@
|
|||
"""Test saving a notebook with escaped characters
|
||||
"""
|
||||
|
||||
from urllib.parse import quote
|
||||
from .utils import wait_for_selector
|
||||
|
||||
promise_js = """
|
||||
var done = arguments[arguments.length - 1];
|
||||
%s.then(
|
||||
data => { done(["success", data]); },
|
||||
error => { done(["error", error]); }
|
||||
);
|
||||
"""
|
||||
|
||||
def execute_promise(js, browser):
|
||||
state, data = browser.execute_async_script(promise_js % js)
|
||||
if state == 'success':
|
||||
return data
|
||||
raise Exception(data)
|
||||
|
||||
|
||||
def test_save(notebook):
|
||||
# don't use unicode with ambiguous composed/decomposed normalization
|
||||
# because the filesystem may use a different normalization than literals.
|
||||
# This causes no actual problems, but will break string comparison.
|
||||
nbname = "has#hash and space and unicø∂e.ipynb"
|
||||
escaped_name = quote(nbname)
|
||||
|
||||
notebook.edit_cell(index=0, content="s = '??'")
|
||||
|
||||
notebook.browser.execute_script("Jupyter.notebook.set_notebook_name(arguments[0])", nbname)
|
||||
|
||||
model = execute_promise("Jupyter.notebook.save_notebook()", notebook.browser)
|
||||
assert model['name'] == nbname
|
||||
|
||||
current_name = notebook.browser.execute_script("return Jupyter.notebook.notebook_name")
|
||||
assert current_name == nbname
|
||||
|
||||
current_path = notebook.browser.execute_script("return Jupyter.notebook.notebook_path")
|
||||
assert current_path == nbname
|
||||
|
||||
displayed_name = notebook.browser.find_element_by_id('notebook_name').text
|
||||
assert displayed_name + '.ipynb' == nbname
|
||||
|
||||
execute_promise("Jupyter.notebook.save_checkpoint()", notebook.browser)
|
||||
|
||||
checkpoints = notebook.browser.execute_script("return Jupyter.notebook.checkpoints")
|
||||
assert len(checkpoints) == 1
|
||||
|
||||
notebook.browser.find_element_by_css_selector('#ipython_notebook a').click()
|
||||
hrefs_nonmatch = []
|
||||
for link in wait_for_selector(notebook.browser, 'a.item_link'):
|
||||
href = link.get_attribute('href')
|
||||
if escaped_name in href:
|
||||
print("Opening", href)
|
||||
notebook.browser.get(href)
|
||||
wait_for_selector(notebook.browser, '.cell')
|
||||
break
|
||||
hrefs_nonmatch.append(href)
|
||||
else:
|
||||
raise AssertionError("{!r} not found in {!r}"
|
||||
.format(escaped_name, hrefs_nonmatch))
|
||||
|
||||
current_name = notebook.browser.execute_script("return Jupyter.notebook.notebook_name")
|
||||
assert current_name == nbname
|
|
@ -0,0 +1,40 @@
|
|||
from notebook.tests.selenium.utils import wait_for_selector
|
||||
from selenium.webdriver.common.keys import Keys
|
||||
from selenium.webdriver.support.ui import WebDriverWait
|
||||
|
||||
def wait_for_rename(browser, nbname, timeout=10):
|
||||
wait = WebDriverWait(browser, timeout)
|
||||
def notebook_renamed(browser):
|
||||
elem = browser.find_element_by_id('notebook_name')
|
||||
current_name = browser.execute_script('return arguments[0].innerText', elem)
|
||||
return current_name == nbname
|
||||
return wait.until(notebook_renamed)
|
||||
|
||||
def save_as(nb):
|
||||
JS = 'Jupyter.notebook.save_notebook_as()'
|
||||
return nb.browser.execute_script(JS)
|
||||
|
||||
def get_notebook_name(nb):
|
||||
JS = 'return Jupyter.notebook.notebook_name'
|
||||
return nb.browser.execute_script(JS)
|
||||
|
||||
def set_notebook_name(nb, name):
|
||||
JS = 'Jupyter.notebook.rename("{}")'.format(name)
|
||||
nb.browser.execute_script(JS)
|
||||
|
||||
def test_save_notebook_as(notebook):
|
||||
# Set a name for comparison later
|
||||
set_notebook_name(notebook, name="nb1.ipynb")
|
||||
wait_for_rename(notebook.browser, "nb1")
|
||||
assert get_notebook_name(notebook) == "nb1.ipynb"
|
||||
# Wait for Save As modal, save
|
||||
save_as(notebook)
|
||||
wait_for_selector(notebook.browser, '.save-message')
|
||||
inp = notebook.browser.find_element_by_xpath('//input[@data-testid="save-as"]')
|
||||
inp.send_keys('new_notebook.ipynb')
|
||||
inp.send_keys(Keys.RETURN)
|
||||
wait_for_rename(notebook.browser, "new_notebook")
|
||||
# Test that the name changed
|
||||
assert get_notebook_name(notebook) == "new_notebook.ipynb"
|
||||
# Test that address bar was updated (TODO: get the base url)
|
||||
assert "new_notebook.ipynb" in notebook.browser.current_url
|
|
@ -0,0 +1,80 @@
|
|||
from notebook.tests.selenium.utils import wait_for_selector, Notebook
|
||||
from selenium.webdriver.common.keys import Keys
|
||||
from selenium.webdriver.support.ui import WebDriverWait
|
||||
|
||||
|
||||
promise_js = """
|
||||
var done = arguments[arguments.length - 1];
|
||||
(%s).then(
|
||||
data => { done(["success", data]); },
|
||||
error => { done(["error", error]); }
|
||||
);
|
||||
"""
|
||||
|
||||
def execute_promise(js, browser):
|
||||
state, data = browser.execute_async_script(promise_js % js)
|
||||
if state == 'success':
|
||||
return data
|
||||
raise Exception(data)
|
||||
|
||||
def wait_for_rename(browser, nbname, timeout=10):
|
||||
wait = WebDriverWait(browser, timeout)
|
||||
def notebook_renamed(browser):
|
||||
elem = browser.find_element_by_id('notebook_name')
|
||||
current_name = browser.execute_script('return arguments[0].innerText', elem)
|
||||
return current_name == nbname
|
||||
return wait.until(notebook_renamed)
|
||||
|
||||
def save_as(nb):
|
||||
JS = 'Jupyter.notebook.save_notebook_as()'
|
||||
return nb.browser.execute_script(JS)
|
||||
|
||||
def get_notebook_name(nb):
|
||||
JS = 'return Jupyter.notebook.notebook_name'
|
||||
return nb.browser.execute_script(JS)
|
||||
|
||||
def refresh_notebook(nb):
|
||||
nb.browser.refresh()
|
||||
nb.__init__(nb.browser)
|
||||
|
||||
def test_save_readonly_notebook_as(notebook):
|
||||
# Make notebook read-only
|
||||
notebook.edit_cell(index=0, content='import os\nimport stat\nos.chmod("'
|
||||
+ notebook.browser.current_url.split('?')[0].split('/')[-1] + '", stat.S_IREAD)\nprint(0)')
|
||||
notebook.browser.execute_script("Jupyter.notebook.get_cell(0).execute();")
|
||||
notebook.wait_for_cell_output(0)
|
||||
refresh_notebook(notebook)
|
||||
# Test that the notebook is read-only
|
||||
assert notebook.browser.execute_script('return Jupyter.notebook.writable') == False
|
||||
|
||||
# Add some content
|
||||
test_content_0 = "print('a simple')\nprint('test script')"
|
||||
notebook.edit_cell(index=0, content=test_content_0)
|
||||
|
||||
# Wait for Save As modal, save
|
||||
save_as(notebook)
|
||||
wait_for_selector(notebook.browser, '.save-message')
|
||||
inp = notebook.browser.find_element_by_xpath('//input[@data-testid="save-as"]')
|
||||
inp.send_keys('writable_notebook.ipynb')
|
||||
inp.send_keys(Keys.RETURN)
|
||||
wait_for_rename(notebook.browser, "writable_notebook")
|
||||
# Test that the name changed
|
||||
assert get_notebook_name(notebook) == "writable_notebook.ipynb"
|
||||
# Test that address bar was updated (TODO: get the base url)
|
||||
assert "writable_notebook.ipynb" in notebook.browser.current_url
|
||||
# Test that it is no longer read-only
|
||||
assert notebook.browser.execute_script('return Jupyter.notebook.writable') == True
|
||||
|
||||
# Add some more content
|
||||
test_content_1 = "print('a second simple')\nprint('script to test save feature')"
|
||||
notebook.add_and_execute_cell(content=test_content_1)
|
||||
# and save the notebook
|
||||
execute_promise("Jupyter.notebook.save_notebook()", notebook.browser)
|
||||
|
||||
# Test that it still contains the content
|
||||
assert notebook.get_cell_contents(index=0) == test_content_0
|
||||
assert notebook.get_cell_contents(index=1) == test_content_1
|
||||
# even after a refresh
|
||||
refresh_notebook(notebook)
|
||||
assert notebook.get_cell_contents(index=0) == test_content_0
|
||||
assert notebook.get_cell_contents(index=1) == test_content_1
|
|
@ -0,0 +1,15 @@
|
|||
"""Tests shutdown of the Kernel."""
|
||||
from .utils import wait_for_selector, wait_for_xpath
|
||||
|
||||
def test_shutdown(notebook):
|
||||
notebook.edit_cell(content="print(21)")
|
||||
wait_for_xpath(notebook.browser, '//a[text()="Kernel"]', single=True).click()
|
||||
wait_for_selector(notebook.browser, '#shutdown_kernel', single=True).click()
|
||||
wait_for_selector(notebook.browser, '.btn.btn-default.btn-sm.btn-danger', single=True).click()
|
||||
|
||||
#Wait until all shutdown modal elements disappear before trying to execute the cell
|
||||
wait_for_xpath(notebook.browser, "//div[contains(@class,'modal')]", obscures=True)
|
||||
notebook.execute_cell(0)
|
||||
|
||||
assert not notebook.is_kernel_running()
|
||||
assert len(notebook.get_cell_output()) == 0
|
|
@ -0,0 +1,92 @@
|
|||
from selenium.webdriver.common.keys import Keys
|
||||
from .utils import shift
|
||||
|
||||
def undelete(nb):
|
||||
nb.browser.execute_script('Jupyter.notebook.undelete_cell();')
|
||||
|
||||
INITIAL_CELLS = ['print("a")', 'print("b")', 'print("c")', 'print("d")']
|
||||
|
||||
def test_undelete_cells(prefill_notebook):
|
||||
notebook = prefill_notebook(INITIAL_CELLS)
|
||||
a, b, c, d = INITIAL_CELLS
|
||||
|
||||
# Verify initial state
|
||||
assert notebook.get_cells_contents() == [a, b, c, d]
|
||||
|
||||
# Delete cells [1, 2]
|
||||
notebook.focus_cell(1)
|
||||
shift(notebook.browser, Keys.DOWN)
|
||||
notebook.current_cell.send_keys('dd')
|
||||
assert notebook.get_cells_contents() == [a, d]
|
||||
|
||||
# Delete new cell 1 (which contains d)
|
||||
notebook.focus_cell(1)
|
||||
notebook.current_cell.send_keys('dd')
|
||||
assert notebook.get_cells_contents() == [a]
|
||||
|
||||
# Undelete d
|
||||
undelete(notebook)
|
||||
assert notebook.get_cells_contents() == [a, d]
|
||||
|
||||
# Undelete b, c
|
||||
undelete(notebook)
|
||||
assert notebook.get_cells_contents() == [a, b, c, d]
|
||||
|
||||
# Nothing more to undelete
|
||||
undelete(notebook)
|
||||
assert notebook.get_cells_contents() == [a, b, c, d]
|
||||
|
||||
# Delete first two cells and restore
|
||||
notebook.focus_cell(0)
|
||||
shift(notebook.browser, Keys.DOWN)
|
||||
notebook.current_cell.send_keys('dd')
|
||||
assert notebook.get_cells_contents() == [c, d]
|
||||
undelete(notebook)
|
||||
assert notebook.get_cells_contents() == [a, b, c, d]
|
||||
|
||||
# Delete last two cells and restore
|
||||
notebook.focus_cell(-1)
|
||||
shift(notebook.browser, Keys.UP)
|
||||
notebook.current_cell.send_keys('dd')
|
||||
assert notebook.get_cells_contents() == [a, b]
|
||||
undelete(notebook)
|
||||
assert notebook.get_cells_contents() == [a, b, c, d]
|
||||
|
||||
# Merge cells [1, 2], restore the deleted one
|
||||
bc = b + "\n\n" + c
|
||||
notebook.focus_cell(1)
|
||||
shift(notebook.browser, 'j')
|
||||
shift(notebook.browser, 'm')
|
||||
assert notebook.get_cells_contents() == [a, bc, d]
|
||||
undelete(notebook)
|
||||
assert notebook.get_cells_contents() == [a, bc, c, d]
|
||||
|
||||
# Merge cells [2, 3], restore the deleted one
|
||||
cd = c + "\n\n" + d
|
||||
notebook.focus_cell(-1)
|
||||
shift(notebook.browser, 'k')
|
||||
shift(notebook.browser, 'm')
|
||||
assert notebook.get_cells_contents() == [a, bc, cd]
|
||||
undelete(notebook)
|
||||
assert notebook.get_cells_contents() == [a, bc, cd, d]
|
||||
|
||||
# Reset contents to [a, b, c, d] --------------------------------------
|
||||
notebook.edit_cell(index=1, content=b)
|
||||
notebook.edit_cell(index=2, content=c)
|
||||
assert notebook.get_cells_contents() == [a, b, c, d]
|
||||
|
||||
# Merge cell below, restore the deleted one
|
||||
ab = a + "\n\n" + b
|
||||
notebook.focus_cell(0)
|
||||
notebook.browser.execute_script("Jupyter.notebook.merge_cell_below();")
|
||||
assert notebook.get_cells_contents() == [ab, c, d]
|
||||
undelete(notebook)
|
||||
assert notebook.get_cells_contents() == [ab, b, c, d]
|
||||
|
||||
# Merge cell above, restore the deleted one
|
||||
cd = c + "\n\n" + d
|
||||
notebook.focus_cell(-1)
|
||||
notebook.browser.execute_script("Jupyter.notebook.merge_cell_above();")
|
||||
assert notebook.get_cells_contents() == [ab, b, cd]
|
||||
undelete(notebook)
|
||||
assert notebook.get_cells_contents() == [ab, b, c, cd]
|
469
venv/Lib/site-packages/notebook/tests/selenium/utils.py
Normal file
469
venv/Lib/site-packages/notebook/tests/selenium/utils.py
Normal file
|
@ -0,0 +1,469 @@
|
|||
import os
|
||||
from selenium.webdriver import ActionChains
|
||||
from selenium.webdriver.common.by import By
|
||||
from selenium.webdriver.common.keys import Keys
|
||||
from selenium.webdriver.support.ui import WebDriverWait
|
||||
from selenium.webdriver.support import expected_conditions as EC
|
||||
from selenium.webdriver.remote.webelement import WebElement
|
||||
|
||||
from contextlib import contextmanager
|
||||
|
||||
pjoin = os.path.join
|
||||
|
||||
|
||||
def wait_for_selector(driver, selector, timeout=10, visible=False, single=False, wait_for_n=1, obscures=False):
|
||||
if wait_for_n > 1:
|
||||
return _wait_for_multiple(
|
||||
driver, By.CSS_SELECTOR, selector, timeout, wait_for_n, visible)
|
||||
return _wait_for(driver, By.CSS_SELECTOR, selector, timeout, visible, single, obscures)
|
||||
|
||||
|
||||
def wait_for_tag(driver, tag, timeout=10, visible=False, single=False, wait_for_n=1, obscures=False):
|
||||
if wait_for_n > 1:
|
||||
return _wait_for_multiple(
|
||||
driver, By.TAG_NAME, tag, timeout, wait_for_n, visible)
|
||||
return _wait_for(driver, By.TAG_NAME, tag, timeout, visible, single, obscures)
|
||||
|
||||
|
||||
def wait_for_xpath(driver, xpath, timeout=10, visible=False, single=False, wait_for_n=1, obscures=False):
|
||||
if wait_for_n > 1:
|
||||
return _wait_for_multiple(
|
||||
driver, By.XPATH, xpath, timeout, wait_for_n, visible)
|
||||
return _wait_for(driver, By.XPATH, xpath, timeout, visible, single, obscures)
|
||||
|
||||
|
||||
def wait_for_script_to_return_true(driver, script, timeout=10):
|
||||
WebDriverWait(driver, timeout).until(lambda d: d.execute_script(script))
|
||||
|
||||
|
||||
def _wait_for(driver, locator_type, locator, timeout=10, visible=False, single=False, obscures=False):
|
||||
"""Waits `timeout` seconds for the specified condition to be met. Condition is
|
||||
met if any matching element is found. Returns located element(s) when found.
|
||||
|
||||
Args:
|
||||
driver: Selenium web driver instance
|
||||
locator_type: type of locator (e.g. By.CSS_SELECTOR or By.TAG_NAME)
|
||||
locator: name of tag, class, etc. to wait for
|
||||
timeout: how long to wait for presence/visibility of element
|
||||
visible: if True, require that element is not only present, but visible
|
||||
single: if True, return a single element, otherwise return a list of matching
|
||||
elements
|
||||
obscures: if True, waits until the element becomes invisible
|
||||
"""
|
||||
wait = WebDriverWait(driver, timeout)
|
||||
if obscures:
|
||||
conditional = EC.invisibility_of_element_located
|
||||
elif single:
|
||||
if visible:
|
||||
conditional = EC.visibility_of_element_located
|
||||
else:
|
||||
conditional = EC.presence_of_element_located
|
||||
else:
|
||||
if visible:
|
||||
conditional = EC.visibility_of_all_elements_located
|
||||
else:
|
||||
conditional = EC.presence_of_all_elements_located
|
||||
return wait.until(conditional((locator_type, locator)))
|
||||
|
||||
|
||||
def _wait_for_multiple(driver, locator_type, locator, timeout, wait_for_n, visible=False):
|
||||
"""Waits until `wait_for_n` matching elements to be present (or visible).
|
||||
Returns located elements when found.
|
||||
|
||||
Args:
|
||||
driver: Selenium web driver instance
|
||||
locator_type: type of locator (e.g. By.CSS_SELECTOR or By.TAG_NAME)
|
||||
locator: name of tag, class, etc. to wait for
|
||||
timeout: how long to wait for presence/visibility of element
|
||||
wait_for_n: wait until this number of matching elements are present/visible
|
||||
visible: if True, require that elements are not only present, but visible
|
||||
"""
|
||||
wait = WebDriverWait(driver, timeout)
|
||||
|
||||
def multiple_found(driver):
|
||||
elements = driver.find_elements(locator_type, locator)
|
||||
if visible:
|
||||
elements = [e for e in elements if e.is_displayed()]
|
||||
if len(elements) < wait_for_n:
|
||||
return False
|
||||
return elements
|
||||
|
||||
return wait.until(multiple_found)
|
||||
|
||||
|
||||
class CellTypeError(ValueError):
|
||||
|
||||
def __init__(self, message=""):
|
||||
self.message = message
|
||||
|
||||
|
||||
class Notebook:
|
||||
|
||||
def __init__(self, browser):
|
||||
self.browser = browser
|
||||
self._wait_for_start()
|
||||
self.disable_autosave_and_onbeforeunload()
|
||||
|
||||
def __len__(self):
|
||||
return len(self.cells)
|
||||
|
||||
def __getitem__(self, key):
|
||||
return self.cells[key]
|
||||
|
||||
def __setitem__(self, key, item):
|
||||
if isinstance(key, int):
|
||||
self.edit_cell(index=key, content=item, render=False)
|
||||
# TODO: re-add slicing support, handle general python slicing behaviour
|
||||
# includes: overwriting the entire self.cells object if you do
|
||||
# self[:] = []
|
||||
# elif isinstance(key, slice):
|
||||
# indices = (self.index(cell) for cell in self[key])
|
||||
# for k, v in zip(indices, item):
|
||||
# self.edit_cell(index=k, content=v, render=False)
|
||||
|
||||
def __iter__(self):
|
||||
return (cell for cell in self.cells)
|
||||
|
||||
def _wait_for_start(self):
|
||||
"""Wait until the notebook interface is loaded and the kernel started"""
|
||||
wait_for_selector(self.browser, '.cell')
|
||||
WebDriverWait(self.browser, 10).until(
|
||||
lambda drvr: self.is_kernel_running()
|
||||
)
|
||||
|
||||
@property
|
||||
def body(self):
|
||||
return self.browser.find_element_by_tag_name("body")
|
||||
|
||||
@property
|
||||
def cells(self):
|
||||
"""Gets all cells once they are visible.
|
||||
|
||||
"""
|
||||
return self.browser.find_elements_by_class_name("cell")
|
||||
|
||||
@property
|
||||
def current_index(self):
|
||||
return self.index(self.current_cell)
|
||||
|
||||
def index(self, cell):
|
||||
return self.cells.index(cell)
|
||||
|
||||
def disable_autosave_and_onbeforeunload(self):
|
||||
"""Disable request to save before closing window and autosave.
|
||||
|
||||
This is most easily done by using js directly.
|
||||
"""
|
||||
self.browser.execute_script("window.onbeforeunload = null;")
|
||||
self.browser.execute_script("Jupyter.notebook.set_autosave_interval(0)")
|
||||
|
||||
def to_command_mode(self):
|
||||
"""Changes us into command mode on currently focused cell
|
||||
|
||||
"""
|
||||
self.body.send_keys(Keys.ESCAPE)
|
||||
self.browser.execute_script("return Jupyter.notebook.handle_command_mode("
|
||||
"Jupyter.notebook.get_cell("
|
||||
"Jupyter.notebook.get_edit_index()))")
|
||||
|
||||
def focus_cell(self, index=0):
|
||||
cell = self.cells[index]
|
||||
cell.click()
|
||||
self.to_command_mode()
|
||||
self.current_cell = cell
|
||||
|
||||
def select_cell_range(self, initial_index=0, final_index=0):
|
||||
self.focus_cell(initial_index)
|
||||
self.to_command_mode()
|
||||
for i in range(final_index - initial_index):
|
||||
shift(self.browser, 'j')
|
||||
|
||||
def find_and_replace(self, index=0, find_txt='', replace_txt=''):
|
||||
self.focus_cell(index)
|
||||
self.to_command_mode()
|
||||
self.body.send_keys('f')
|
||||
wait_for_selector(self.browser, "#find-and-replace", single=True)
|
||||
self.browser.find_element_by_id("findreplace_allcells_btn").click()
|
||||
self.browser.find_element_by_id("findreplace_find_inp").send_keys(find_txt)
|
||||
self.browser.find_element_by_id("findreplace_replace_inp").send_keys(replace_txt)
|
||||
self.browser.find_element_by_id("findreplace_replaceall_btn").click()
|
||||
|
||||
def convert_cell_type(self, index=0, cell_type="code"):
|
||||
# TODO add check to see if it is already present
|
||||
self.focus_cell(index)
|
||||
cell = self.cells[index]
|
||||
if cell_type == "markdown":
|
||||
self.current_cell.send_keys("m")
|
||||
elif cell_type == "raw":
|
||||
self.current_cell.send_keys("r")
|
||||
elif cell_type == "code":
|
||||
self.current_cell.send_keys("y")
|
||||
else:
|
||||
raise CellTypeError(("{} is not a valid cell type,"
|
||||
"use 'code', 'markdown', or 'raw'").format(cell_type))
|
||||
|
||||
self.wait_for_stale_cell(cell)
|
||||
self.focus_cell(index)
|
||||
return self.current_cell
|
||||
|
||||
def wait_for_stale_cell(self, cell):
|
||||
""" This is needed to switch a cell's mode and refocus it, or to render it.
|
||||
|
||||
Warning: there is currently no way to do this when changing between
|
||||
markdown and raw cells.
|
||||
"""
|
||||
wait = WebDriverWait(self.browser, 10)
|
||||
element = wait.until(EC.staleness_of(cell))
|
||||
|
||||
def wait_for_element_availability(self, element):
|
||||
_wait_for(self.browser, By.CLASS_NAME, element, visible=True)
|
||||
|
||||
def get_cells_contents(self):
|
||||
JS = 'return Jupyter.notebook.get_cells().map(function(c) {return c.get_text();})'
|
||||
return self.browser.execute_script(JS)
|
||||
|
||||
def get_cell_contents(self, index=0, selector='div .CodeMirror-code'):
|
||||
return self.cells[index].find_element_by_css_selector(selector).text
|
||||
|
||||
def get_cell_output(self, index=0, output='output_subarea'):
|
||||
return self.cells[index].find_elements_by_class_name(output)
|
||||
|
||||
def wait_for_cell_output(self, index=0, timeout=10):
|
||||
return WebDriverWait(self.browser, timeout).until(
|
||||
lambda b: self.get_cell_output(index)
|
||||
)
|
||||
|
||||
def set_cell_metadata(self, index, key, value):
|
||||
JS = 'Jupyter.notebook.get_cell({}).metadata.{} = {}'.format(index, key, value)
|
||||
return self.browser.execute_script(JS)
|
||||
|
||||
def get_cell_type(self, index=0):
|
||||
JS = 'return Jupyter.notebook.get_cell({}).cell_type'.format(index)
|
||||
return self.browser.execute_script(JS)
|
||||
|
||||
def set_cell_input_prompt(self, index, prmpt_val):
|
||||
JS = 'Jupyter.notebook.get_cell({}).set_input_prompt({})'.format(index, prmpt_val)
|
||||
self.browser.execute_script(JS)
|
||||
|
||||
def edit_cell(self, cell=None, index=0, content="", render=False):
|
||||
"""Set the contents of a cell to *content*, by cell object or by index
|
||||
"""
|
||||
if cell is not None:
|
||||
index = self.index(cell)
|
||||
self.focus_cell(index)
|
||||
|
||||
# Select & delete anything already in the cell
|
||||
self.current_cell.send_keys(Keys.ENTER)
|
||||
cmdtrl(self.browser, 'a')
|
||||
self.current_cell.send_keys(Keys.DELETE)
|
||||
|
||||
for line_no, line in enumerate(content.splitlines()):
|
||||
if line_no != 0:
|
||||
self.current_cell.send_keys(Keys.ENTER, "\n")
|
||||
self.current_cell.send_keys(Keys.ENTER, line)
|
||||
if render:
|
||||
self.execute_cell(self.current_index)
|
||||
|
||||
def execute_cell(self, cell_or_index=None):
|
||||
if isinstance(cell_or_index, int):
|
||||
index = cell_or_index
|
||||
elif isinstance(cell_or_index, WebElement):
|
||||
index = self.index(cell_or_index)
|
||||
else:
|
||||
raise TypeError("execute_cell only accepts a WebElement or an int")
|
||||
self.focus_cell(index)
|
||||
self.current_cell.send_keys(Keys.CONTROL, Keys.ENTER)
|
||||
|
||||
def add_cell(self, index=-1, cell_type="code", content=""):
|
||||
self.focus_cell(index)
|
||||
self.current_cell.send_keys("b")
|
||||
new_index = index + 1 if index >= 0 else index
|
||||
if content:
|
||||
self.edit_cell(index=index, content=content)
|
||||
if cell_type != 'code':
|
||||
self.convert_cell_type(index=new_index, cell_type=cell_type)
|
||||
|
||||
def add_and_execute_cell(self, index=-1, cell_type="code", content=""):
|
||||
self.add_cell(index=index, cell_type=cell_type, content=content)
|
||||
self.execute_cell(index)
|
||||
|
||||
def delete_cell(self, index):
|
||||
self.focus_cell(index)
|
||||
self.to_command_mode()
|
||||
self.current_cell.send_keys('dd')
|
||||
|
||||
def add_markdown_cell(self, index=-1, content="", render=True):
|
||||
self.add_cell(index, cell_type="markdown")
|
||||
self.edit_cell(index=index, content=content, render=render)
|
||||
|
||||
def append(self, *values, cell_type="code"):
|
||||
for i, value in enumerate(values):
|
||||
if isinstance(value, str):
|
||||
self.add_cell(cell_type=cell_type,
|
||||
content=value)
|
||||
else:
|
||||
raise TypeError("Don't know how to add cell from %r" % value)
|
||||
|
||||
def extend(self, values):
|
||||
self.append(*values)
|
||||
|
||||
def run_all(self):
|
||||
for cell in self:
|
||||
self.execute_cell(cell)
|
||||
|
||||
def trigger_keydown(self, keys):
|
||||
trigger_keystrokes(self.body, keys)
|
||||
|
||||
def is_kernel_running(self):
|
||||
return self.browser.execute_script(
|
||||
"return Jupyter.notebook.kernel && Jupyter.notebook.kernel.is_connected()"
|
||||
)
|
||||
|
||||
def clear_cell_output(self, index):
|
||||
JS = 'Jupyter.notebook.clear_output({})'.format(index)
|
||||
self.browser.execute_script(JS)
|
||||
|
||||
@classmethod
|
||||
def new_notebook(cls, browser, kernel_name='kernel-python3'):
|
||||
with new_window(browser):
|
||||
select_kernel(browser, kernel_name=kernel_name)
|
||||
return cls(browser)
|
||||
|
||||
|
||||
def select_kernel(browser, kernel_name='kernel-python3'):
|
||||
"""Clicks the "new" button and selects a kernel from the options.
|
||||
"""
|
||||
wait = WebDriverWait(browser, 10)
|
||||
new_button = wait.until(EC.element_to_be_clickable((By.ID, "new-dropdown-button")))
|
||||
new_button.click()
|
||||
kernel_selector = '#{} a'.format(kernel_name)
|
||||
kernel = wait_for_selector(browser, kernel_selector, single=True)
|
||||
kernel.click()
|
||||
|
||||
|
||||
@contextmanager
|
||||
def new_window(browser):
|
||||
"""Contextmanager for switching to & waiting for a window created.
|
||||
|
||||
This context manager gives you the ability to create a new window inside
|
||||
the created context and it will switch you to that new window.
|
||||
|
||||
Usage example:
|
||||
|
||||
from notebook.tests.selenium.utils import new_window, Notebook
|
||||
|
||||
⋮ # something that creates a browser object
|
||||
|
||||
with new_window(browser):
|
||||
select_kernel(browser, kernel_name=kernel_name)
|
||||
nb = Notebook(browser)
|
||||
|
||||
"""
|
||||
initial_window_handles = browser.window_handles
|
||||
yield
|
||||
new_window_handles = [window for window in browser.window_handles
|
||||
if window not in initial_window_handles]
|
||||
if not new_window_handles:
|
||||
raise Exception("No new windows opened during context")
|
||||
browser.switch_to.window(new_window_handles[0])
|
||||
|
||||
def shift(browser, k):
|
||||
"""Send key combination Shift+(k)"""
|
||||
trigger_keystrokes(browser, "shift-%s"%k)
|
||||
|
||||
def cmdtrl(browser, k):
|
||||
"""Send key combination Ctrl+(k) or Command+(k) for MacOS"""
|
||||
trigger_keystrokes(browser, "command-%s"%k) if os.uname()[0] == "Darwin" else trigger_keystrokes(browser, "control-%s"%k)
|
||||
|
||||
def alt(browser, k):
|
||||
"""Send key combination Alt+(k)"""
|
||||
trigger_keystrokes(browser, 'alt-%s'%k)
|
||||
|
||||
def trigger_keystrokes(browser, *keys):
|
||||
""" Send the keys in sequence to the browser.
|
||||
Handles following key combinations
|
||||
1. with modifiers eg. 'control-alt-a', 'shift-c'
|
||||
2. just modifiers eg. 'alt', 'esc'
|
||||
3. non-modifiers eg. 'abc'
|
||||
Modifiers : http://seleniumhq.github.io/selenium/docs/api/py/webdriver/selenium.webdriver.common.keys.html
|
||||
"""
|
||||
for each_key_combination in keys:
|
||||
keys = each_key_combination.split('-')
|
||||
if len(keys) > 1: # key has modifiers eg. control, alt, shift
|
||||
modifiers_keys = [getattr(Keys, x.upper()) for x in keys[:-1]]
|
||||
ac = ActionChains(browser)
|
||||
for i in modifiers_keys: ac = ac.key_down(i)
|
||||
ac.send_keys(keys[-1])
|
||||
for i in modifiers_keys[::-1]: ac = ac.key_up(i)
|
||||
ac.perform()
|
||||
else: # single key stroke. Check if modifier eg. "up"
|
||||
browser.send_keys(getattr(Keys, keys[0].upper(), keys[0]))
|
||||
|
||||
def validate_dualmode_state(notebook, mode, index):
|
||||
'''Validate the entire dual mode state of the notebook.
|
||||
Checks if the specified cell is selected, and the mode and keyboard mode are the same.
|
||||
Depending on the mode given:
|
||||
Command: Checks that no cells are in focus or in edit mode.
|
||||
Edit: Checks that only the specified cell is in focus and in edit mode.
|
||||
'''
|
||||
def is_only_cell_edit(index):
|
||||
JS = 'return Jupyter.notebook.get_cells().map(function(c) {return c.mode;})'
|
||||
cells_mode = notebook.browser.execute_script(JS)
|
||||
#None of the cells are in edit mode
|
||||
if index is None:
|
||||
for mode in cells_mode:
|
||||
if mode == 'edit':
|
||||
return False
|
||||
return True
|
||||
#Only the index cell is on edit mode
|
||||
for i, mode in enumerate(cells_mode):
|
||||
if i == index:
|
||||
if mode != 'edit':
|
||||
return False
|
||||
else:
|
||||
if mode == 'edit':
|
||||
return False
|
||||
return True
|
||||
|
||||
def is_focused_on(index):
|
||||
JS = "return $('#notebook .CodeMirror-focused textarea').length;"
|
||||
focused_cells = notebook.browser.execute_script(JS)
|
||||
if index is None:
|
||||
return focused_cells == 0
|
||||
|
||||
if focused_cells != 1: #only one cell is focused
|
||||
return False
|
||||
|
||||
JS = "return $('#notebook .CodeMirror-focused textarea')[0];"
|
||||
focused_cell = notebook.browser.execute_script(JS)
|
||||
JS = "return IPython.notebook.get_cell(%s).code_mirror.getInputField()"%index
|
||||
cell = notebook.browser.execute_script(JS)
|
||||
return focused_cell == cell
|
||||
|
||||
|
||||
#general test
|
||||
JS = "return IPython.keyboard_manager.mode;"
|
||||
keyboard_mode = notebook.browser.execute_script(JS)
|
||||
JS = "return IPython.notebook.mode;"
|
||||
notebook_mode = notebook.browser.execute_script(JS)
|
||||
|
||||
#validate selected cell
|
||||
JS = "return Jupyter.notebook.get_selected_cells_indices();"
|
||||
cell_index = notebook.browser.execute_script(JS)
|
||||
assert cell_index == [index] #only the index cell is selected
|
||||
|
||||
if mode != 'command' and mode != 'edit':
|
||||
raise Exception('An unknown mode was send: mode = "%s"'%mode) #An unknown mode is send
|
||||
|
||||
#validate mode
|
||||
assert mode == keyboard_mode #keyboard mode is correct
|
||||
|
||||
if mode == 'command':
|
||||
assert is_focused_on(None) #no focused cells
|
||||
|
||||
assert is_only_cell_edit(None) #no cells in edit mode
|
||||
|
||||
elif mode == 'edit':
|
||||
assert is_focused_on(index) #The specified cell is focused
|
||||
|
||||
assert is_only_cell_edit(index) #The specified cell is the only one in edit mode
|
325
venv/Lib/site-packages/notebook/tests/services/kernel.js
Normal file
325
venv/Lib/site-packages/notebook/tests/services/kernel.js
Normal file
|
@ -0,0 +1,325 @@
|
|||
|
||||
//
|
||||
// Kernel tests
|
||||
//
|
||||
casper.notebook_test(function () {
|
||||
// test that the kernel is running
|
||||
this.then(function () {
|
||||
this.test.assert(this.kernel_running(), 'kernel is running');
|
||||
});
|
||||
|
||||
// test list
|
||||
this.thenEvaluate(function () {
|
||||
IPython._kernels = null;
|
||||
IPython.notebook.kernel.list(function (data) {
|
||||
IPython._kernels = data;
|
||||
});
|
||||
});
|
||||
this.waitFor(function () {
|
||||
return this.evaluate(function () {
|
||||
return IPython._kernels !== null;
|
||||
});
|
||||
});
|
||||
this.then(function () {
|
||||
var num_kernels = this.evaluate(function () {
|
||||
return IPython._kernels.length;
|
||||
});
|
||||
this.test.assertEquals(num_kernels, 1, 'one kernel running');
|
||||
});
|
||||
|
||||
// test get_info
|
||||
var kernel_info = this.evaluate(function () {
|
||||
return {
|
||||
name: IPython.notebook.kernel.name,
|
||||
id: IPython.notebook.kernel.id
|
||||
};
|
||||
});
|
||||
this.thenEvaluate(function () {
|
||||
IPython._kernel_info = null;
|
||||
IPython.notebook.kernel.get_info(function (data) {
|
||||
IPython._kernel_info = data;
|
||||
});
|
||||
});
|
||||
this.waitFor(function () {
|
||||
return this.evaluate(function () {
|
||||
return IPython._kernel_info !== null;
|
||||
});
|
||||
});
|
||||
this.then(function () {
|
||||
var new_kernel_info = this.evaluate(function () {
|
||||
return IPython._kernel_info;
|
||||
});
|
||||
this.test.assertEquals(kernel_info.name, new_kernel_info.name, 'kernel: name correct');
|
||||
this.test.assertEquals(kernel_info.id, new_kernel_info.id, 'kernel: id correct');
|
||||
});
|
||||
|
||||
// test interrupt
|
||||
this.thenEvaluate(function () {
|
||||
IPython._interrupted = false;
|
||||
IPython.notebook.kernel.interrupt(function () {
|
||||
IPython._interrupted = true;
|
||||
});
|
||||
});
|
||||
this.waitFor(function () {
|
||||
return this.evaluate(function () {
|
||||
return IPython._interrupted;
|
||||
});
|
||||
});
|
||||
this.then(function () {
|
||||
var interrupted = this.evaluate(function () {
|
||||
return IPython._interrupted;
|
||||
});
|
||||
this.test.assert(interrupted, 'kernel was interrupted');
|
||||
});
|
||||
|
||||
// test restart
|
||||
this.thenEvaluate(function () {
|
||||
IPython.notebook.kernel.restart();
|
||||
});
|
||||
this.waitFor(this.kernel_disconnected);
|
||||
this.wait_for_kernel_ready();
|
||||
this.then(function () {
|
||||
this.test.assert(this.kernel_running(), 'kernel restarted');
|
||||
});
|
||||
|
||||
// test reconnect
|
||||
this.thenEvaluate(function () {
|
||||
IPython.notebook.kernel.stop_channels();
|
||||
});
|
||||
this.waitFor(this.kernel_disconnected);
|
||||
this.thenEvaluate(function () {
|
||||
IPython.notebook.kernel.reconnect();
|
||||
});
|
||||
this.wait_for_kernel_ready();
|
||||
this.then(function () {
|
||||
this.test.assert(this.kernel_running(), 'kernel reconnected');
|
||||
});
|
||||
|
||||
// test kernel_info_request
|
||||
this.evaluate(function () {
|
||||
IPython.notebook.kernel.kernel_info(
|
||||
function(msg){
|
||||
IPython._kernel_info_response = msg;
|
||||
});
|
||||
});
|
||||
this.waitFor(
|
||||
function () {
|
||||
return this.evaluate(function(){
|
||||
return IPython._kernel_info_response;
|
||||
});
|
||||
});
|
||||
this.then(function () {
|
||||
var kernel_info_response = this.evaluate(function(){
|
||||
return IPython._kernel_info_response;
|
||||
});
|
||||
this.test.assertTrue( kernel_info_response.msg_type === 'kernel_info_reply', 'Kernel info request return kernel_info_reply');
|
||||
this.test.assertTrue( kernel_info_response.content !== undefined, 'Kernel_info_reply is not undefined');
|
||||
});
|
||||
|
||||
// test kill
|
||||
this.thenEvaluate(function () {
|
||||
IPython.notebook.kernel.kill();
|
||||
});
|
||||
this.waitFor(this.kernel_disconnected);
|
||||
this.then(function () {
|
||||
this.test.assert(!this.kernel_running(), 'kernel is not running');
|
||||
});
|
||||
|
||||
// test start
|
||||
var url, base_url;
|
||||
this.then(function () {
|
||||
base_url = this.evaluate(function () {
|
||||
return IPython.notebook.base_url;
|
||||
});
|
||||
url = this.evaluate(function () {
|
||||
return IPython.notebook.kernel.start();
|
||||
});
|
||||
});
|
||||
this.then(function () {
|
||||
this.test.assertEquals(url, base_url + "api/kernels", "start url is correct");
|
||||
});
|
||||
this.wait_for_kernel_ready();
|
||||
this.then(function () {
|
||||
this.test.assert(this.kernel_running(), 'kernel is running');
|
||||
});
|
||||
|
||||
// test start with parameters
|
||||
this.thenEvaluate(function () {
|
||||
IPython.notebook.kernel.kill();
|
||||
});
|
||||
this.waitFor(this.kernel_disconnected);
|
||||
this.then(function () {
|
||||
url = this.evaluate(function () {
|
||||
return IPython.notebook.kernel.start({foo: "bar"});
|
||||
});
|
||||
});
|
||||
this.then(function () {
|
||||
this.test.assertEquals(url, base_url + "api/kernels?foo=bar", "start url with params is correct");
|
||||
});
|
||||
this.wait_for_kernel_ready();
|
||||
this.then(function () {
|
||||
this.test.assert(this.kernel_running(), 'kernel is running');
|
||||
});
|
||||
|
||||
// check for events in kill/start cycle
|
||||
this.event_test(
|
||||
'kill/start',
|
||||
[
|
||||
'kernel_killed.Kernel',
|
||||
'kernel_starting.Kernel',
|
||||
'kernel_created.Kernel',
|
||||
'kernel_connected.Kernel',
|
||||
'kernel_ready.Kernel'
|
||||
],
|
||||
function () {
|
||||
this.thenEvaluate(function () {
|
||||
IPython.notebook.kernel.kill();
|
||||
});
|
||||
this.waitFor(this.kernel_disconnected);
|
||||
this.thenEvaluate(function () {
|
||||
IPython.notebook.kernel.start();
|
||||
});
|
||||
}
|
||||
);
|
||||
// wait for any last idle/busy messages to be handled
|
||||
this.wait_for_kernel_ready();
|
||||
|
||||
// check for events in disconnect/connect cycle
|
||||
this.event_test(
|
||||
'reconnect',
|
||||
[
|
||||
'kernel_reconnecting.Kernel',
|
||||
'kernel_connected.Kernel',
|
||||
],
|
||||
function () {
|
||||
this.thenEvaluate(function () {
|
||||
IPython.notebook.kernel.stop_channels();
|
||||
IPython.notebook.kernel.reconnect(1);
|
||||
});
|
||||
}
|
||||
);
|
||||
// wait for any last idle/busy messages to be handled
|
||||
this.wait_for_kernel_ready();
|
||||
|
||||
// check for events in the restart cycle
|
||||
this.event_test(
|
||||
'restart',
|
||||
[
|
||||
'kernel_restarting.Kernel',
|
||||
'kernel_created.Kernel',
|
||||
'kernel_connected.Kernel',
|
||||
'kernel_ready.Kernel'
|
||||
],
|
||||
function () {
|
||||
this.thenEvaluate(function () {
|
||||
IPython.notebook.kernel.restart();
|
||||
});
|
||||
}
|
||||
);
|
||||
// wait for any last idle/busy messages to be handled
|
||||
this.wait_for_kernel_ready();
|
||||
|
||||
// check for events in the interrupt cycle
|
||||
this.event_test(
|
||||
'interrupt',
|
||||
[
|
||||
'kernel_interrupting.Kernel',
|
||||
'kernel_busy.Kernel',
|
||||
'kernel_idle.Kernel'
|
||||
],
|
||||
function () {
|
||||
this.thenEvaluate(function () {
|
||||
IPython.notebook.kernel.interrupt();
|
||||
});
|
||||
}
|
||||
);
|
||||
this.wait_for_kernel_ready();
|
||||
|
||||
// check for events after ws close
|
||||
this.event_test(
|
||||
'ws_closed_ok',
|
||||
[
|
||||
'kernel_disconnected.Kernel',
|
||||
'kernel_reconnecting.Kernel',
|
||||
'kernel_connected.Kernel',
|
||||
'kernel_busy.Kernel',
|
||||
'kernel_idle.Kernel'
|
||||
],
|
||||
function () {
|
||||
this.thenEvaluate(function () {
|
||||
IPython.notebook.kernel._ws_closed("", false);
|
||||
});
|
||||
}
|
||||
);
|
||||
// wait for any last idle/busy messages to be handled
|
||||
this.wait_for_kernel_ready();
|
||||
|
||||
// check for events after ws close (error)
|
||||
this.event_test(
|
||||
'ws_closed_error',
|
||||
[
|
||||
'kernel_disconnected.Kernel',
|
||||
'kernel_connection_failed.Kernel',
|
||||
'kernel_reconnecting.Kernel',
|
||||
'kernel_connected.Kernel',
|
||||
'kernel_busy.Kernel',
|
||||
'kernel_idle.Kernel'
|
||||
],
|
||||
function () {
|
||||
this.thenEvaluate(function () {
|
||||
IPython.notebook.kernel._ws_closed("", true);
|
||||
});
|
||||
}
|
||||
);
|
||||
// wait for any last idle/busy messages to be handled
|
||||
this.wait_for_kernel_ready();
|
||||
|
||||
// start the kernel back up
|
||||
this.thenEvaluate(function () {
|
||||
IPython.notebook.kernel.restart();
|
||||
});
|
||||
this.waitFor(this.kernel_running);
|
||||
this.wait_for_kernel_ready();
|
||||
|
||||
// test handling of autorestarting messages
|
||||
this.event_test(
|
||||
'autorestarting',
|
||||
[
|
||||
'kernel_restarting.Kernel',
|
||||
'kernel_autorestarting.Kernel',
|
||||
],
|
||||
function () {
|
||||
this.thenEvaluate(function () {
|
||||
var cell = IPython.notebook.get_cell(0);
|
||||
cell.set_text('import os\n' + 'os._exit(1)');
|
||||
cell.execute();
|
||||
});
|
||||
}
|
||||
);
|
||||
this.wait_for_kernel_ready();
|
||||
|
||||
// test handling of failed restart
|
||||
this.event_test(
|
||||
'failed_restart',
|
||||
[
|
||||
'kernel_restarting.Kernel',
|
||||
'kernel_autorestarting.Kernel',
|
||||
'kernel_dead.Kernel'
|
||||
],
|
||||
function () {
|
||||
this.thenEvaluate(function () {
|
||||
var cell = IPython.notebook.get_cell(0);
|
||||
cell.set_text("import os\n" +
|
||||
"from IPython.kernel.connect import get_connection_file\n" +
|
||||
"with open(get_connection_file(), 'w') as f:\n" +
|
||||
" f.write('garbage')\n" +
|
||||
"os._exit(1)");
|
||||
cell.execute();
|
||||
});
|
||||
},
|
||||
|
||||
// need an extra-long timeout, because it needs to try
|
||||
// restarting the kernel 5 times!
|
||||
20000
|
||||
);
|
||||
});
|
123
venv/Lib/site-packages/notebook/tests/services/serialize.js
Normal file
123
venv/Lib/site-packages/notebook/tests/services/serialize.js
Normal file
|
@ -0,0 +1,123 @@
|
|||
//
|
||||
// Test binary messages on websockets.
|
||||
// Only works on slimer for now, due to old websocket impl in phantomjs.
|
||||
//
|
||||
|
||||
casper.notebook_test(function () {
|
||||
// create EchoBuffers target on js-side.
|
||||
// it just captures and echos comm messages.
|
||||
this.then(function () {
|
||||
var success = this.evaluate(function () {
|
||||
IPython._msgs = [];
|
||||
|
||||
var EchoBuffers = function(comm) {
|
||||
this.comm = comm;
|
||||
this.comm.on_msg($.proxy(this.on_msg, this));
|
||||
};
|
||||
|
||||
EchoBuffers.prototype.on_msg = function (msg) {
|
||||
IPython._msgs.push(msg);
|
||||
this.comm.send(msg.content.data, {}, {}, msg.buffers);
|
||||
};
|
||||
|
||||
IPython.notebook.kernel.comm_manager.register_target("echo", function (comm) {
|
||||
return new EchoBuffers(comm);
|
||||
});
|
||||
|
||||
return true;
|
||||
});
|
||||
this.test.assertEquals(success, true, "Created echo comm target");
|
||||
});
|
||||
|
||||
// Create a similar comm that captures messages Python-side
|
||||
this.then(function () {
|
||||
var index = this.append_cell([
|
||||
"import os",
|
||||
"from IPython.kernel.comm import Comm",
|
||||
"comm = Comm(target_name='echo')",
|
||||
"msgs = []",
|
||||
"def on_msg(msg):",
|
||||
" msgs.append(msg)",
|
||||
"comm.on_msg(on_msg)"
|
||||
].join('\n'), 'code');
|
||||
this.execute_cell(index);
|
||||
});
|
||||
|
||||
// send a message with binary data
|
||||
this.then(function () {
|
||||
var index = this.append_cell([
|
||||
"buffers = [b'\\xFF\\x00', b'\\x00\\x01\\x02']",
|
||||
"comm.send(data='message 0', buffers=buffers)",
|
||||
"comm.send(data='message 1')",
|
||||
"comm.send(data='message 2', buffers=buffers)",
|
||||
].join('\n'), 'code');
|
||||
this.execute_cell(index);
|
||||
});
|
||||
|
||||
// wait for capture
|
||||
this.waitFor(function () {
|
||||
return this.evaluate(function () {
|
||||
return IPython._msgs.length >= 3;
|
||||
});
|
||||
});
|
||||
|
||||
// validate captured buffers js-side
|
||||
this.then(function () {
|
||||
var msgs = this.evaluate(function () {
|
||||
return IPython._msgs;
|
||||
});
|
||||
this.test.assertEquals(msgs.length, 3, "Captured three comm messages");
|
||||
|
||||
|
||||
|
||||
// check the messages came in the right order
|
||||
this.test.assertEquals(msgs[0].content.data, "message 0", "message 0 processed first");
|
||||
this.test.assertEquals(msgs[0].buffers.length, 2, "comm message 0 has two buffers");
|
||||
this.test.assertEquals(msgs[1].content.data, "message 1", "message 1 processed second");
|
||||
this.test.assertEquals(msgs[1].buffers.length, 0, "comm message 1 has no buffers");
|
||||
this.test.assertEquals(msgs[2].content.data, "message 2", "message 2 processed third");
|
||||
this.test.assertEquals(msgs[2].buffers.length, 2, "comm message 2 has two buffers");
|
||||
|
||||
// extract attributes to test in evaluate,
|
||||
// because the raw DataViews can't be passed across
|
||||
var buf_info = function (message, index) {
|
||||
var buf = IPython._msgs[message].buffers[index];
|
||||
var data = {};
|
||||
data.byteLength = buf.byteLength;
|
||||
data.bytes = [];
|
||||
for (var i = 0; i < data.byteLength; i++) {
|
||||
data.bytes.push(buf.getUint8(i));
|
||||
}
|
||||
return data;
|
||||
};
|
||||
|
||||
var msgs_with_buffers = [0, 2];
|
||||
for (var i = 0; i < msgs_with_buffers.length; i++) {
|
||||
msg_index = msgs_with_buffers[i];
|
||||
buf0 = this.evaluate(buf_info, msg_index, 0);
|
||||
buf1 = this.evaluate(buf_info, msg_index, 1);
|
||||
this.test.assertEquals(buf0.byteLength, 2, 'buf[0] has correct size in message '+msg_index);
|
||||
this.test.assertEquals(buf0.bytes, [255, 0], 'buf[0] has correct bytes in message '+msg_index);
|
||||
this.test.assertEquals(buf1.byteLength, 3, 'buf[1] has correct size in message '+msg_index);
|
||||
this.test.assertEquals(buf1.bytes, [0, 1, 2], 'buf[1] has correct bytes in message '+msg_index);
|
||||
}
|
||||
});
|
||||
|
||||
// validate captured buffers Python-side
|
||||
this.then(function () {
|
||||
var index = this.append_cell([
|
||||
"assert len(msgs) == 3, len(msgs)",
|
||||
"bufs = msgs[0]['buffers']",
|
||||
"assert len(bufs) == len(buffers), bufs",
|
||||
"assert bufs[0].tobytes() == buffers[0], bufs[0]",
|
||||
"assert bufs[1].tobytes() == buffers[1], bufs[1]",
|
||||
"1",
|
||||
].join('\n'), 'code');
|
||||
this.execute_cell(index);
|
||||
this.wait_for_output(index);
|
||||
this.then(function () {
|
||||
var out = this.get_output_cell(index);
|
||||
this.test.assertEquals(out.data['text/plain'], '1', "Python received buffers");
|
||||
});
|
||||
});
|
||||
});
|
186
venv/Lib/site-packages/notebook/tests/services/session.js
Normal file
186
venv/Lib/site-packages/notebook/tests/services/session.js
Normal file
|
@ -0,0 +1,186 @@
|
|||
|
||||
//
|
||||
// Tests for the Session object
|
||||
//
|
||||
|
||||
casper.notebook_test(function () {
|
||||
var that = this;
|
||||
var get_info = function () {
|
||||
return that.evaluate(function () {
|
||||
return JSON.parse(JSON.stringify(IPython.notebook.session._get_model()));
|
||||
});
|
||||
};
|
||||
|
||||
// test that the kernel is running
|
||||
this.then(function () {
|
||||
this.test.assert(this.kernel_running(), 'session: kernel is running');
|
||||
});
|
||||
|
||||
// test list
|
||||
this.thenEvaluate(function () {
|
||||
IPython._sessions = null;
|
||||
IPython.notebook.session.list(function (data) {
|
||||
IPython._sessions = data;
|
||||
});
|
||||
});
|
||||
this.waitFor(function () {
|
||||
return this.evaluate(function () {
|
||||
return IPython._sessions !== null;
|
||||
});
|
||||
});
|
||||
this.then(function () {
|
||||
var num_sessions = this.evaluate(function () {
|
||||
return IPython._sessions.length;
|
||||
});
|
||||
this.test.assertEquals(num_sessions, 1, 'one session running');
|
||||
});
|
||||
|
||||
// test get_info
|
||||
var session_info = get_info();
|
||||
this.thenEvaluate(function () {
|
||||
IPython._session_info = null;
|
||||
IPython.notebook.session.get_info(function (data) {
|
||||
IPython._session_info = data;
|
||||
});
|
||||
});
|
||||
this.waitFor(function () {
|
||||
return this.evaluate(function () {
|
||||
return IPython._session_info !== null;
|
||||
});
|
||||
});
|
||||
this.then(function () {
|
||||
var new_session_info = this.evaluate(function () {
|
||||
return IPython._session_info;
|
||||
});
|
||||
this.test.assertEquals(session_info.name, new_session_info.name, 'session: notebook name correct');
|
||||
this.test.assertEquals(session_info.path, new_session_info.path, 'session: notebook path correct');
|
||||
this.test.assertEquals(session_info.kernel.name, new_session_info.kernel.name, 'session: kernel name correct');
|
||||
this.test.assertEquals(session_info.kernel.id, new_session_info.kernel.id, 'session: kernel id correct');
|
||||
});
|
||||
|
||||
// test rename_notebook
|
||||
//
|
||||
// TODO: the PATCH request isn't supported by phantom, so this test always
|
||||
// fails, see https://github.com/ariya/phantomjs/issues/11384
|
||||
// when this is fixed we can properly run this test
|
||||
//
|
||||
// this.thenEvaluate(function () {
|
||||
// IPython._renamed = false;
|
||||
// IPython.notebook.session.rename_notebook(
|
||||
// "foo",
|
||||
// "bar",
|
||||
// function (data) {
|
||||
// IPython._renamed = true;
|
||||
// }
|
||||
// );
|
||||
// });
|
||||
// this.waitFor(function () {
|
||||
// return this.evaluate(function () {
|
||||
// return IPython._renamed;
|
||||
// });
|
||||
// });
|
||||
// this.then(function () {
|
||||
// var info = get_info();
|
||||
// this.test.assertEquals(info.notebook.name, "foo", "notebook was renamed");
|
||||
// this.test.assertEquals(info.notebook.path, "bar", "notebook path was changed");
|
||||
// });
|
||||
|
||||
// test delete
|
||||
this.thenEvaluate(function () {
|
||||
IPython.notebook.session.delete();
|
||||
});
|
||||
this.waitFor(this.kernel_disconnected);
|
||||
this.then(function () {
|
||||
this.test.assert(!this.kernel_running(), 'session deletes kernel');
|
||||
});
|
||||
|
||||
// check for events when starting the session
|
||||
this.event_test(
|
||||
'start_session',
|
||||
[
|
||||
'kernel_created.Session',
|
||||
'kernel_connected.Kernel',
|
||||
'kernel_ready.Kernel'
|
||||
],
|
||||
function () {
|
||||
this.thenEvaluate(function () {
|
||||
IPython.notebook.session.start();
|
||||
});
|
||||
}
|
||||
);
|
||||
this.wait_for_kernel_ready();
|
||||
|
||||
// check for events when killing the session
|
||||
this.event_test(
|
||||
'delete_session',
|
||||
['kernel_killed.Session'],
|
||||
function () {
|
||||
this.thenEvaluate(function () {
|
||||
IPython.notebook.session.delete();
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
this.thenEvaluate( function() {IPython.notebook.session.start()});
|
||||
this.wait_for_kernel_ready();
|
||||
|
||||
// check for events when restarting the session
|
||||
this.event_test(
|
||||
'restart_session',
|
||||
[
|
||||
'kernel_killed.Session',
|
||||
'kernel_created.Session',
|
||||
'kernel_connected.Kernel',
|
||||
'kernel_ready.Kernel'
|
||||
],
|
||||
function () {
|
||||
this.thenEvaluate(function () {
|
||||
IPython.notebook.session.restart();
|
||||
});
|
||||
}
|
||||
);
|
||||
this.wait_for_kernel_ready();
|
||||
|
||||
// test handling of failed restart
|
||||
this.event_test(
|
||||
'failed_restart',
|
||||
[
|
||||
'kernel_restarting.Kernel',
|
||||
'kernel_autorestarting.Kernel',
|
||||
'kernel_killed.Session',
|
||||
'kernel_dead.Kernel',
|
||||
],
|
||||
function () {
|
||||
this.thenEvaluate(function () {
|
||||
var cell = IPython.notebook.get_cell(0);
|
||||
cell.set_text("import os\n" +
|
||||
"from IPython.kernel.connect import get_connection_file\n" +
|
||||
"with open(get_connection_file(), 'w') as f:\n" +
|
||||
" f.write('garbage')\n" +
|
||||
"os._exit(1)");
|
||||
cell.execute();
|
||||
});
|
||||
},
|
||||
|
||||
// need an extra-long timeout, because it needs to try
|
||||
// restarting the kernel 5 times!
|
||||
20000
|
||||
);
|
||||
|
||||
this.thenEvaluate( function() {IPython.notebook.session.start()});
|
||||
this.wait_for_kernel_ready();
|
||||
|
||||
// check for events when starting a nonexistent kernel
|
||||
this.event_test(
|
||||
'bad_start_session',
|
||||
[
|
||||
'kernel_killed.Session',
|
||||
'kernel_dead.Session'
|
||||
],
|
||||
function () {
|
||||
this.thenEvaluate(function () {
|
||||
IPython.notebook.session.restart({kernel_name: 'foo'});
|
||||
});
|
||||
}
|
||||
);
|
||||
});
|
57
venv/Lib/site-packages/notebook/tests/test_config_manager.py
Normal file
57
venv/Lib/site-packages/notebook/tests/test_config_manager.py
Normal file
|
@ -0,0 +1,57 @@
|
|||
import json
|
||||
import os
|
||||
import shutil
|
||||
import tempfile
|
||||
|
||||
from notebook.config_manager import BaseJSONConfigManager
|
||||
|
||||
|
||||
def test_json():
|
||||
tmpdir = tempfile.mkdtemp()
|
||||
try:
|
||||
root_data = dict(a=1, x=2, nest={'a':1, 'x':2})
|
||||
with open(os.path.join(tmpdir, 'foo.json'), 'w') as f:
|
||||
json.dump(root_data, f)
|
||||
# also make a foo.d/ directory with multiple json files
|
||||
os.makedirs(os.path.join(tmpdir, 'foo.d'))
|
||||
with open(os.path.join(tmpdir, 'foo.d', 'a.json'), 'w') as f:
|
||||
json.dump(dict(a=2, b=1, nest={'a':2, 'b':1}), f)
|
||||
with open(os.path.join(tmpdir, 'foo.d', 'b.json'), 'w') as f:
|
||||
json.dump(dict(a=3, b=2, c=3, nest={'a':3, 'b':2, 'c':3}, only_in_b={'x':1}), f)
|
||||
manager = BaseJSONConfigManager(config_dir=tmpdir, read_directory=False)
|
||||
data = manager.get('foo')
|
||||
assert 'a' in data
|
||||
assert 'x' in data
|
||||
assert 'b' not in data
|
||||
assert 'c' not in data
|
||||
assert data['a'] == 1
|
||||
assert 'x' in data['nest']
|
||||
# if we write it out, it also shouldn't pick up the subdirectory
|
||||
manager.set('foo', data)
|
||||
data = manager.get('foo')
|
||||
assert data == root_data
|
||||
|
||||
manager = BaseJSONConfigManager(config_dir=tmpdir, read_directory=True)
|
||||
data = manager.get('foo')
|
||||
assert 'a' in data
|
||||
assert 'b' in data
|
||||
assert 'c' in data
|
||||
# files should be read in order foo.d/a.json foo.d/b.json foo.json
|
||||
assert data['a'] == 1
|
||||
assert data['b'] == 2
|
||||
assert data['c'] == 3
|
||||
assert data['nest']['a'] == 1
|
||||
assert data['nest']['b'] == 2
|
||||
assert data['nest']['c'] == 3
|
||||
assert data['nest']['x'] == 2
|
||||
|
||||
# when writing out, we don't want foo.d/*.json data to be included in the root foo.json
|
||||
manager.set('foo', data)
|
||||
manager = BaseJSONConfigManager(config_dir=tmpdir, read_directory=False)
|
||||
data = manager.get('foo')
|
||||
assert data == root_data
|
||||
|
||||
finally:
|
||||
shutil.rmtree(tmpdir)
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue